Time difference is zero in second calculation of division in c# - c#

I need to calculate the time difference faken for division most accurately in nano seconds. Please tell me to do this.
At Present i'm using a lower accuracy method in which the problem is that : when the first calculation is performed it shows 87 milliseconds or 65 milliseconds as answer. But when the function is called again second time or more, it only show 0 milliseconds.
The code is :
long startTick = DateTime.Now.Ticks;
double result = (double)22 / 7;
result = System.Math.Round(result, digit);
long endTick = DateTime.Now.Ticks;
long tick = endTick - startTick;
double milliseconds = tick / TimeSpan.TicksPerMillisecond;
time.Text = result + "\nThe division took " + milliseconds + " milliseconds to complete.";
digit is the parameter of function which is variable. No matter what the value of digit is the milliseconds value remains 0 after first calling of function....
Please suggest more accurate way in which calling the same function with different decimal digits will result in different time interval in c# for windows Phone.
I think the memory flush should be done before and after each calculation. But i dont know how to do this.
I don't like this tick method personally for accuracy. I've tried stopwatch also but its not working. Please suggest another method best suited in my case. I want result like : 0.0345 or 0.0714 seconds.
Thanks

You are performing integer division on this line:
double milliseconds = tick / TimeSpan.TicksPerMillisecond;
Even though you are declaring it as a double, a long divided by a long will truncate the decimal. You are better off doing:
double milliseconds = (double)tick / TimeSpan.TicksPerMillisecond;
Or better yet, just ditch the tick stuff all together:
DateTime start = DateTime.Now;
double result = (double)22 / 7;
result = System.Math.Round(result, digit);
DateTime end = DateTime.Now;
double milliseconds = (end - start).TotalMilliseconds;
time.Text = result + "\nThe division took " + milliseconds + " milliseconds to complete.";
You won't be able to get micro or nano level precision, but you will get millisecond precision with a margin of error.
You still may get zero, however. You are trying to time how long a simple division operation takes. You could do millions of division operations in less than a second. You may want to do it 1,000,000 times, then divide the result by a 1,000,000:
DateTime start = DateTime.Now;
for (var i = 0; i < 1000000; i++)
{
double result = (double)22 / 7;
result = System.Math.Round(result, digit);
}
DateTime end = DateTime.Now;
double milliseconds = (end - start).TotalMilliseconds / 1000000;
This still won't be completely realistic, but should get you an actual number.

Since you have the time in ticks, just increase the resolution by multiplying the denominator:
double microseconds = tick / (TimeSpan.TicksPerMillisecond * 1000.0);

Why are you not using StopWatch Class to do your time calulation.
It is meant to the calculate the time the you want ..
Here is a link for your reference.
http://msdn.microsoft.com/en-us/library/system.diagnostics.stopwatch.aspx

//if you want to get the full milliseconds you could also do something like this.
dateStartTime = Convert.ToDateTime(DateTime.Now.TimeOfDay.ToString());
//then where you end the code do this
dateEndTime = Convert.ToDateTime(DateTime.Now.TimeOfDay.ToString());
ddateDuration = (TimeSpan)(dateEndTime - dateStartTime);
then to display out what you are actually looking for in terms of miliseconds do
Console.WriteLine(ddateDuration.ToString().Substring(0, 8));
// or some other method that you are using to display the results

Related

How to Calculate with TimeSpan in c#

I need to divide two TimeSpan.
I have one TimeSpan "worktime" and the other TimeSpan "productive"
What i want is to get as result of worktime/productive is a percentage. I need to get the "added value" (<- I think this is how it's called in english :)),
In .NET Core you can simply divide the TimeSpans. TimeSpan has a division operator.
This works:
var t1=TimeSpan.FromTicks(1000);
var t2=TimeSpan.FromTicks(100);
Console.WriteLine(t2/t1);
---------------------
0.1 ```
A Simple example:
DateTime d1 = DateTime.Parse("10:00:00");
DateTime d2 = DateTime.Parse("13:00:00");
TimeSpan t1 = d2 - d1; // three hours
TimeSpan t2 = new TimeSpan(0,15,0); // 15 minutes
Console.WriteLine(t1/t2);
This outputs: 12
see: https://onlinegdb.com/ImxwiWk37
var addedValue = (decimal)workTime.Ticks/productive.Ticks * 100;
The decimal cast is needed or the division will automatically round and you'll get very inaccurate percentages in certain cases.
I need to get the "added value"
By this, do you mean you want the percentage expressed as a percentage of the overall work time that was productive?
So if the total work time was 10 hours and the productive work time was 9 hours, the percentage of productive work time would be 90%?
If so, the answer is:
double percentage = double percentage = 100.0 - 100.0 * (worktime.Ticks - productive.Ticks) / worktime.Ticks;

How to multiply a timespan by a decimal?

I'm working on a project which calculates a cost of calls from two different times entered by the user. I've parsed the data into the code as DateTime.
DateTime starttime = new DateTime(Convert.ToDateTime(cal1.SelectedDate).Year,Convert.ToDateTime(cal1.SelectedDate).Month,Convert.ToDateTime(cal1.SelectedDate).Day,
Convert.ToInt32(drpdwn1.SelectedValue),
Convert.ToInt32(drpdwn2.SelectedValue),
Convert.ToInt32(drpdwn3.SelectedValue));
DateTime endtime = new DateTime(Convert.ToDateTime(cal1.SelectedDate).Year, Convert.ToDateTime(cal1.SelectedDate).Month, Convert.ToDateTime(cal1.SelectedDate).Day,
Convert.ToInt32(drpdwn4.SelectedValue),
Convert.ToInt32(drpdwn5.SelectedValue),
Convert.ToInt32(drpdwn6.SelectedValue));
And subtracts the two to get a timespan.
TimeSpan duration3 = (endtime - starttime);
txtDisplay.Text = duration3.ToString();
Can someone help me find a way to multiply $0.35 to the timespan duration3?
Here is what I'm using right now but the textbox keeps displaying 0
double mins = duration3.Minutes;
double hrs = duration3.Hours;
double cost = ((hrs * 60) + mins) * 0.35;
txtCost.Text = cost.ToString();
//$0.35/min
// ((0.35*60)*hr + 0.35*min)
Possibly something like:
static decimal Foo(TimeSpan duration, decimal perMinuteRate)
=> ((decimal)duration.TotalMinutes) * perMinuteRate;
although note that TotalMinutes is a double, so this could have unexpected rounding if your duration is very fractional.
Better to do it this way, so you don't interfer with double precision errors:
public static decimal MultiplyPerMinute(TimeSpan a, decimal b)
{
return a.Ticks * b / TimeSpan.TicksPerMinute;
}
When you work with decimal, only double or float should scare you off in any possible operator. Decimal is a type made specificaly for digital, and precision durable operations.
As written, the question is not very clear. There are two questions really:
How to multiply a TimeSpan by a decimal?
Why is my TextBox always displaying zero?
Question 1 is not clear - it can be interpreted in many ways. From reading the posted code, comments and other answers it is possible to see that you are trying to calculate the "cost of a TimeSpan given the cost per minute". Why not ask this question?
But that isn't really your question - your posted code does indicate that you have an idea about how to calculate the "cost of a TimeSpan given the cost per minute", the problem is that your "textbox keeps displaying 0".
From the code posted, I don't know why this is. However, following some good debugging practices should fairly quickly help you narrow down the problem yourself.
See this link to a post by Eric Lippert that you should find useful:
How to debug small programs
No need to calculate the minutes yourself - and multiplying is easy:
TimeSpan ts = DateTime.Now - DateTime.Today;
var cost = ((int)ts.TotalMinutes) * 0.35m; // cost per minute, edited wrongly used 0.63m
I am int ing out the decimals of TotalMinutes to avoid billing for 23.2832s as well ;)

Rounding FILETIME in C# to accommodate FAT rounding

I have a Windows FILETIME :
A 64-bit value representing the number of 100-nanosecond intervals
since January 1, 1601 (UTC))
and I need it rounded UP to the nearest even second, as described here.
The code I have so far:
var originalDt = DateTime.FromFileTimeUtc(input);
// round it UP to the nearest Second
var newDt = originalDt.AddMilliseconds(1000 - originalDt.Millisecond);
// then if our new Second isn't even
if (newDt.Second % 2 != 0)
{
// add one second to it, then it'll be even
newDt = newDt.AddSeconds(1);
}
return newDt.ToFileTimeUtc();
doesn't quite work... it turns 130790247821478763 into 130790247820008763, I'm after 130790247800000000.
Maths isn't my strongest subject... can I just zero those last four digits safely? Or should I forget the above code and just zero the last eight digits completely? Or... another way?
Rather than struggling with the DateTime object, you could perhaps more easily just do the raw mathematics:
If input is the number of 100 nanoseconds, then:
/10 for the number of microseconds;
/10,000 for the number of milliseconds;
/10,000,000 for the number of seconds;
/20,000,000 for the number of 'two-seconds';
So:
input = input / 20000000 * 20000000;
The division will round the number DOWN to the last even second, then the multiply will get it back into the right size again.
But you said you wanted it rounded UP:
input = (input / 20000000 + 1) * 20000000;
That adds one 'two-second' to the small number before factoring it up again.
Pedantically, if input was at exactly the two-second mark, then this would add two seconds to it. To fix that:
if (input % 20000000!=0) {
input = (input / 20000000 + 1) * 20000000;
} // if
That checks whether there's any fractional 'two-second' before deciding to bump it up. I'll leave it up to you as to whether you add this extra check...
#Matthew Watson points out that the usual programmers trick for the above problem is to pre-add not quite enough to roll input over to the next 'two-second', then go ahead and do the divide-then-multiply. If input was over the minimum, that'll roll it over:
const long twoSeconds = 20000000;
...
input = (input + twoSeconds - 1) / twoSeconds * twoSeconds;
Work with raw ticks, then round these up to two-second intervals. This is simpler than trying to add or remove things after the comma.
const long twoSecondsInTicks = 20000000; // 20 million
long twoSecondIntervals = originalDt.Ticks / twoSecondsInTicks;
if (originalDt.Ticks % twoSecondsInTicks != 0) ++twoSecondIntervals;
var newDt = new DateTime(twoSecondIntervals * twoSecondsInTicks);
Your problem is in the rounding up to the nearest second line:
// round it UP to the nearest Second
var newDt = originalDt.AddMilliseconds(1000 - originalDt.Millisecond);
you leave intact fractions of milliseconds (since originalDt.Millisecond is a integer value), micro- and nano- seconds; it should be
// round it UP to the nearest Second
var newDt = originalDt.AddTicks( - (originalDt.Ticks % TimeSpan.TicksPerSecond));
when working with ticks, the smallest possible datetime unit, you'll get expected 130790247820000000 without nanoseconds (...8763)

Someone stole my minute :/

I am trying to convert a time represented in double, something like 23.40 which means 23 hours and 40 minutes, using the following method:
private TimeSpan DoubleToTimeSpan(double time)
{
double hour = Math.Floor(time);
double minute = (time - hour) * 100d;
TimeSpan ts = new TimeSpan((int)hour, (int)minute, 0);
return ts;
}
When testing it on some times, like 23.40 for example:
Console.WriteLine(DoubleToTimeSpan(23.40));
It shows 23:39:00, a whole minute has been stolen by the system! Where is my minute?
Note: I know about TimeSpan.FromHours, this doesn't help me because this method considers the minutes as percentage, so 23.40 is 23 hours and 40% of an hour, which is 23:24:00.
Since 0.4 cannot be exactly represented in the Double floating-point format, you get its nearest representation, which in the case of (23.4-23)*100 is probably something like 39.999999999999858. When you use (int), you truncate the fraction, leaving you with 39.
You need to round instead of truncate, so use (int)Math.Round(minute).
Alternatively, you can use the Decimal type, which can exactly represent decimal numbers like 23.40.
Try rounding it instead of int
private TimeSpan DoubleToTimeSpan(double time)
{
double hour = Math.Floor(time);
hour.Dump();
double minute = (time - hour) * 100d;
minute.Dump();
TimeSpan ts = new TimeSpan((int)hour, (int)Math.Round(minute), 0);
return ts;
}
If you do just (int)minute it will take the integer part of your double.
When you cast from a double to an int, it's truncating your value for minute -- thus your lost minute.
(time - hour) * 100d
Will evaluate to 39.999999999999858, and thus 39 when casting to int.
You've used Math.Floor for the hour, so use Math.Ceiling for the minute. It seems to work ok.
private static TimeSpan DoubleToTimeSpan(double time)
{
return new TimeSpan((int)Math.Floor(time), (int)Math.Ceiling((time - Math.Floor(time)) * 100d), 0);
}
Another option to use decimals. This will prevent precision loss.
decimal minute = ((decimal)time)-((decimal)hour)*100;
Not sure if it's a better solution, but if you're on .NET 4.0 or later, you can also go through a string. It seems like "23.40" is a sequence of characters with one interpretation as a double, and another one as a TimeSpan.
If you like that idea, use:
TimeSpan DoubleToTimeSpan(double time)
{
string str = time.ToString("F2", CultureInfo.InvariantCulture);
TimeSpan ts = TimeSpan.ParseExact(str, "h'.'mm", CultureInfo.InvariantCulture);
return ts;
}
Maybe not as fast as the multiply-by-100-and-round approach, though I haven't tested that.

Unexpected decimal value behavior

I used to think I understand the difference between decimal and double values, but now I'm not able to justify the behavior of this code snippet.
I need to divide the difference between two decimal numbers in some intervals, for example:
decimal minimum = 0.158;
decimal maximum = 64.0;
decimal delta = (maximum - minimum) / 6; // 10.640333333333333333333333333
Then I create the intervals in reverse order, but the first result is already unexpected:
for (int i = 5; i >= 0; i--)
{
Interval interval = new Interval(minimum + (delta * i), minimum + (delta * (i + 1));
}
{53.359666666666666666666666665, 63.999999999999999999999999998}
I would expect the maximum value to be exactly 64. What am I missing here?
Thank you very much!
EDIT: if I use double instead of decimal it seems to works properly!
You're not missing anything. This is the result of rounding the numbers multiple times internally, i.e. compounding loss of precision. The delta, to begin with, isn't exactly 10.640333333333333333333333333, but the 3s keep repeating endlessly, resulting in a loss of precision when you multiply or divide using this decimal.
Maybe you could do it like this instead:
for (decimal i = maximum; i >= delta; i -= delta)
{
Interval interval = new Interval(i - delta, i);
}
Double has 16 digits precision while Decimal has 29 digits precision. Thus, double is more than likely would round it off than decimal.

Categories

Resources