Rounding FILETIME in C# to accommodate FAT rounding - c#

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)

Related

How to distribute a decimal by .5 as evenly as possible with no rounding

I have an input number that is guaranteed to be specified as n.0 or n.5
Example inputs (only a single input is provided):
0
0.5
13.0
13.5
13337.5
28091.0
I need to distribute this number by n values so that all values total the input exactly, but all values must be n.0 or n.5 with NO rounding allowed.
For example, if 13.5 is input and needs to be distributed between 4, the resulting values would be:
3.5
3.5
3.5
3.0
Another example, if 1.0 is specified and needs to be distributed between 4, the resulting values would be:
0.5
0.5
0.0
0.0
I'm thinking the function signature would look similar to:
private List<decimal> DistributeEvenly(decimal amount, int numDistributions)
{
...
}
I do find examples of how to distribute numbers evenly, but not with the n.0 and n.5 requirement and also not without rounding. How can this be accomplished?
I would just divide the input amount by the number of distributions, ignoring any remainder and use that as the base value. Then take the remainder and subtract 0.5 for each distribution until it is gone. Something like this:
private List<decimal> DistributeEvenly(decimal amount, int numDistributions)
{
var result = new List<decimal>();
//Determines the whole number part of each distribution
decimal baseValue = (int)(amount / numDistributions);
//Fill the list with the baseValue, numDistributions times
result.AddRange(Enumerable.Repeat(baseValue, numDistributions));
//The remainder will be distributed in amounts of 0.5 until it runs out
decimal remainder = amount - (baseValue * numDistributions);
int index = 0;
while (remainder > 0)
{
result[index] += 0.5m;
index++;
if (index >= numDistributions)
{
index = 0;
}
remainder -= 0.5m;
}
return result;
}
If you find the total of the numbers you're given and divide by the number of outputs required, you get the mean that's needed. If you divide this mean value by one-half (equivalently: multiply it by 2), take the floor of the result, and then multiply the result of that by one-half, you get the smaller of the two distinct numbers that need to be in your output list. It is simple from there to work out how many of the output numbers need to be increased by one-half.
Just multiply every number by two, and then distribute them evenly by increments of 1 in a for loop until your total is 0. Divide the result by 2. (Or just do it with floats, but you might get rounding errors)

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.

Time difference is zero in second calculation of division in 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

How to convert number to next higher multiple of five?

I am coding a program where a form opens for a certain period of time before closing. I am giving the users to specify the time in seconds. But i'd like this to be in mutliples of five. Or the number gets rounded off to the nearest multiple.
if they enter 1 - 4, then the value is automatically set to 5.
If they enter 6 - 10 then the value is automatically set to 10.
max value is 60, min is 0.
what i have, but i am not happy with this logic since it resets it to 10 seconds.
if (Convert.ToInt32(maskedTextBox1.Text) >= 60 || Convert.ToInt32(maskedTextBox1.Text) <= 0)
mySettings.ToastFormTimer = 10000;
else
mySettings.ToastFormTimer = Convert.ToInt32 (maskedTextBox1.Text) * 1000;
use the Modulus Operator
if(num % 5 == 0)
{
// the number is a multiple of 5.
}
what about this:
int x = int.Parse(maskedTextBox1.Text)/5;
int y = Math.Min(Math.Max(x,1),12)*5; // between [5,60]
// use y as the answer you need
5 * ((num - 1) / 5 + 1)
Should work if c# does integer division.
For the higher goal of rounding to the upper multiple of 5, you don't need to test whether a number is a multiple. Generally speaking, you can round-up or round-to-nearest by adding a constant, then rounding down. To round up, the constant is one less than n. Rounding an integer down to a multiple of n is simple: divide by n and multiply the result by n. Here's a case where rounding error works in your favor.
int ceil_n(int x, int n) {
return ((x+n-1) / n) * n;
}
In dynamic languages that cast the result of integer division to prevent rounding error (which doesn't include C#), you'd need to cast the quotient back to an integer.
Dividing by n can be viewed as a right-shift by 1 place in base n; similarly, multiplying by n is equivalent to a left-shift by 1. This is why the above approach works: it sets the least-significant digit of the number in base n to 0.
2410=445, 2510=505, 2610=515
((445+4 = 535) >>5 1) <<5 1 = 505 = 2510
((505+4 = 545) >>5 1) <<5 1 = 505 = 2510
((515+4 = 605) >>5 1) <<5 1 = 605 = 3010
Another way of zeroing the LSD is to subtract the remainder to set the least significant base n digit to 0, as Jeras does in his comment.
int ceil_n(int x, int n) {
x += n-1;
return x - x%n;
}

Evenly divide a dollar amount (decimal) by an integer

I need to write an accounting routine for a program I am building that will give me an even division of a decimal by an integer. So that for example:
$143.13 / 5 =
28.62
28.62
28.63
28.63
28.63
I have seen the article here: Evenly divide in c#, but it seems like it only works for integer divisions. Any idea of an elegant solution to this problem?
Calculate the amounts one at a time, and subtract each amount from the total to make sure that you always have the correct total left:
decimal total = 143.13m;
int divider = 5;
while (divider > 0) {
decimal amount = Math.Round(total / divider, 2);
Console.WriteLine(amount);
total -= amount;
divider--;
}
result:
28,63
28,62
28,63
28,62
28,63
You can solve this (in cents) without constructing an array:
int a = 100 * amount;
int low_value = a / n;
int high_value = low_value + 1;
int num_highs = a % n;
int num_lows = n - num_highs;
It's easier to deal with cents. I would suggest that instead of 143.13, you divide 14313 into 5 equal parts. Which gives you 2862 and a remainder of 3. You can assign this remainder to the first three parts or any way you like. Finally, convert the cents back to dollars.
Also notice that you will always get a remainder less than the number of parts you want.
First of all, make sure you don't use a floating point number to represent dollars and cents (see other posts for why, but the simple reason is that not all decimal numbers can be represented as floats, e.g., $1.79).
Here's one way of doing it:
decimal total = 143.13m;
int numberOfEntries = 5;
decimal unadjustedEntryAmount = total / numberOfEntries;
decimal leftoverAmount = total - (unadjustedEntryAmount * numberOfEntries);
int numberOfPenniesToDistribute = leftoverAmount * 100;
int numberOfUnadjustedEntries = numberOfEntries - numberOfPenniesToDistribute;
So now you have the unadjusted amounts of 28.62, and then you have to decide how to distribute the remainder. You can either distribute an extra penny to each one starting at the top or at the bottom (looks like you want from the bottom).
for (int i = 0; i < numberOfUnadjustedEntries; i++) {
Console.WriteLine(unadjustedEntryAmount);
}
for (int i = 0; i < numberOfPenniesToDistribute; i++) {
Console.WriteLine(unadjustedEntryAmount + 0.01m);
}
You could also add the entire remainder to the first or last entries. Finally, depending on the accounting needs, you could also create a separate transaction for the remainder.
If you have a float that is guaranteed exactly two digits of precision, what about this (pseudocode):
amount = amount * 100 (convert to cents)
int[] amounts = new int[divisor]
for (i = 0; i < divisor; i++) amounts[i] = amount / divisor
extra = amount % divisor
for (i = 0; i < extra; i++) amounts[i]++
and then do whatever you want with amounts, which are in cents - you could convert back to floats if you absolutely had to, or format as dollars and cents.
If not clear, the point of all this is not just to divide a float value evenly but to divide a monetary amount as evenly as possible, given that cents are an indivisible unit of USD. To the OP: let me know if this isn't what you wanted.
You can use the algorithm in the question you're referencing by multipling by 100, using the integer evenly divide function, and then dividing each of the results by 100 (assuming you only want to handle 2 dp, if you want 3dp multiple by 1000 etc)
It is also possible to use C# iterator generation to make Guffa's answer more convenient:
public static IEnumerable<decimal> Divide(decimal amount, int numBuckets)
{
while(numBuckets > 0)
{
// determine the next amount to return...
var partialAmount = Math.Round(amount / numBuckets, 2);
yield return partialAmount;
// reduce th remaining amount and #buckets
// to account for previously yielded values
amount -= partialAmount;
numBuckets--;
}
}

Categories

Resources