How do I truncate milliseconds off "Ticks" without converting to datetime? - c#

I have two times in Ticks like so:
//2016-01-22​T17:34:52.648Z
var tick1 = 635890808926480754;
//2016-01-22​T17:34:52.000Z
var tick2 = 635890808920000000;
Now as you can see comparing these two numbers tick1 == tick2 returns false
although the dates are the same (apart from milliseconds).
I would like to truncate the milliseconds off these numbers without converting it to a datetime (because this would reduce efficiency)
I have looked at Math.Round which says:
Rounds a value to the nearest integer or to the specified number of fractional digits.
and also Math.Truncate neither of which I think do what I need.
Looking at Datetime.Ticks it says:
A single tick represents one hundred nanoseconds or one ten-millionth of a second. There are 10,000 ticks in a millisecond, or 10 million ticks in a second.
Therefore I need to round the number down to the nearest ten million.
Is this possible?

You could use integer division:
if (tick1 / TimeSpan.TicksPerSecond == tick2 / TimeSpan.TicksPerSecond)
This works because if you divide a long/int by a long/int the result is also a long/int therefore truncating the decimal portion.

You can use this:
if(Math.Abs(tick1 - tick2) < TimeSpan.TicksPerSecond)
Which avoid doing divisions.
You may adjust the precision you need with any of the following:
TimeSpan.TicksPerDay
TimeSpan.TicksPerHour
TimeSpan.TicksPerMinute
TimeSpan.TicksPerSecond
TimeSpan.TicksPerMillisecond

Divide it by 1000 like this:
Long Seconds = 635890808926480754/1000
//Seconds = 635890808926480

Related

Convert double to string fraction in C#

Is there a easy way to convert say 1.3333333 to say 1+1/3 in C#? There is code for just the fraction but not the whole number. Should I just pull that out before using the fraction?
I think it will be hard. Two reasons:
A fraction can always be converted to a decimal number, but a decimal sometimes looses digits, so a exact roundtrip would be impossible. For example: Which number qualifies to be converted to 1/3?:
0.33?
0.333333?
0.333333333333333333333333333333333333333333333333333333333333333333?
Each decimal number can be converted to multible fractions. For example: 0.25 can be converted to:
1/4
2/8
25/100
However, if you are open for some less exact solutions, try: Algorithm for simplifying decimal to fractions
You should set max denominator for example 1 000 000 (one milione) and try to shorten. You have to aware of could lose precision
For example you have 1,450
You take fraction part and multiple by your denominator, it is 450 000 / 1 000 000
Then you find "greatest common divisor"
Divide both part by divisor from previous point
Finally you get your fraction 9/20

Accuracy of decimal

I use the decimal type for high precise calculation (monetary).
But I came across this simple division today:
1 / (1 / 37) which should result in 37 again
http://www.wolframalpha.com/input/?i=1%2F+%281%2F37%29
But C# gives me:
37.000000000000000000000000037M
I tried both these:
1m/(1m/37m);
and
Decimal.Divide(1, Decimal.Divide(1, 37))
but both yield the same results. How is the behaviour explainable?
Decimal stores the value as decimal floating point with only limited precision. The result of 1 / 37 is not precicely stored, as it's stored as 0.027027027027027027027027027M. The true number has the group 027 going indefinitely in decimal representation. For that reason, you cannot get the precise numbers in decimal representation for every possible number.
If you use Double in the same calculation, the end result is correct in this case (but it does not mean it will always be better).
A good answer on that topic is here: Difference between decimal, float and double in .NET?
Decimal data type has an accuracy of 28-29 significant digits.
So what you have to understand is when you consider 28-29 significant digits you are still not exact.
So when you compute a decimal value for (1/37) what you have to note is that at this stage you are only getting an accuracy of 28-29 digits. e.g 1/37 is 0.02 when you take 2 significant digits and 0.027 when you take 3 significant digits. Imagine you divide 1 with these values in each case. you get a 50 in first case and in second case you get 37.02...Considering 28-29 digits (decimal ) takes you to an accuracy of 37.000000000000000000000000037. If you have to get an exact 37 you simply need more than 28-29 significant digits than the decimal offers.
Always do computations with maximum significant digits and round off only your answer with Math.Round for desired result.

Unexpected Behavior of Math.Floor(double) and Math.Ceiling(double)

This question is about the threshold at which Math.Floor(double) and Math.Ceiling(double) decide to give you the previous or next integer value. I was disturbed to find that the threshold seems to have nothing to do with Double.Epsilon, which is the smallest value that can be represented with a double. For example:
double x = 3.0;
Console.WriteLine( Math.Floor( x - Double.Epsilon ) ); // expected 2, got 3
Console.WriteLine( Math.Ceiling( x + Double.Epsilon) ); // expected 4, got 3
Even multiplying Double.Epsilon by a fair bit didn't do the trick:
Console.WriteLine( Math.Floor( x - Double.Epsilon*1000 ) ); // expected 2, got 3
Console.WriteLine( Math.Ceiling( x + Double.Epsilon*1000) ); // expected 4, got 3
With some experimentation, I was able to determine that the threshold is somewhere around 2.2E-16, which is very small, but VASTLY bigger than Double.Epsilon.
The reason this question came up is that I was trying to calculate the number of digits in a number with the formula var digits = Math.Floor( Math.Log( n, 10 ) ) + 1. This formula doesn't work for n=1000 (which I stumbled on completely by accident) because Math.Log( 1000, 10 ) returns a number that's 4.44E-16 off its actual value. (I later found that the built-in Math.Log10(double) provides much more accurate results.)
Shouldn't the threshold should be tied to Double.Epsilon or, if not, shouldn't the threshold be documented (I couldn't find any mention of this in the official MSDN documentation)?
Shouldn't the threshold should be tied to Double.Epsilon
No.
The representable doubles are not uniformly distributed over the real numbers. Close to zero there are many representable values. But the further from zero you get, the further apart representable doubles are. For very large numbers even adding 1 to a double will not give you a new value.
Therefore the threshold you are looking for depends on how large your number is. It is not a constant.
The value of Double.Epsilon is 4.94065645841247e-324. Adding or subtracting this value to 3 results in 3, due to the way floating-point works.
A double has 53 bits of mantissa, so the smallest value you can add that will have any impact will be approximately 2^53 time smaller than your variable. So something around 1e-16 sounds about right (order of magnitude).
So to answer your question: there is no "threshold"; floor and ceil simply act on their argument in exactly the way you would expect.
This is going to be hand-waving rather than references to specifications, but I hope my "intuitive explanation" suits you well.
Epsilon represents the smallest magnitude that can be represented, that is different from zero. Considering the mantissa and exponent of a double, that's going to be extremely tiny -- think 10^-324. There's over three hundred zeros between the decimal point and the first non-zero digit.
However, a Double represents roughly 14-15 digits of precision. That still leaves 310 digits of zeros between Epsilon and and integers.
Doubles are fixed to a certain bit length. If you really want arbitrary precision calculations, you should use an arbitrary-precision library instead. And be prepared for it to be significantly slower -- representing all 325 digits that would be necessary to store a number such as 2+epsilon will require roughly 75 times more storage per number. That storage isn't free and calculating with it certainly cannot go at full CPU speed.

TimeSpan FromMilliseconds strange implementation?

I recently encountered some weird behaviour in the .NET TimeSpan implementation.
TimeSpan test = TimeSpan.FromMilliseconds(0.5);
double ms = test.TotalMilliseconds; // Returns 0
FromMilliseconds takes a double as parameter. However, it seems the value is rounded internally.
If I instantiate a new TimeSpan with 5000 ticks (.5 ms), the value of TotalMilliseconds is correct.
Looking at the TimeSpan implementation in reflector reveals that the input is in fact casted to a long.
Why did Microsoft design the FromMilliseconds method to take a double a parameter instead of a long (since a double value is useless given this implementation)?
The first consideration is wondering why they selected a double as the return value. Using long would have been an obvious choice. Although there already is a perfectly good property that is long, Ticks is unambiguous with a unit of 100 nanoseconds. But they picked double, probably with the intention to return a fractional value.
That however created a new problem, one that was possibly only discovered later. A double can store only 15 significant digits. A TimeSpan can store 10,000 years. It is very desirable to convert from TimeSpan to milliseconds, then back to TimeSpan and get the same value.
That isn't possible with a double. Doing the math: 10,000 years is roughly 10000 x 365.4 x 24 x 3600 x 1000 = 315,705,600,000,000 milliseconds. Count off 15 digits, best a double can do, and you get exactly one millisecond as the smallest unit that can still be stored without round-off error. Any extra digits will be random noise.
Stuck between a rock and a hard place, the designers (testers?) had to choose between rounding the value when converting from TimeSpan to milliseconds. Or to do it later when going from milliseconds to TimeSpan. They chose to do it early, a courageous decision.
Solve your problem by using the Ticks property and multiplying by 1E-4 to get milliseconds.
This is by design, obviously. The documentation says as much:
The value parameter is converted to
ticks, and that number of ticks is
used to initialize the new TimeSpan.
Therefore, value will only be
considered accurate to the nearest
millisecond.
Accepting a double is a logical design. You can have fractions of milliseconds.
What's happening internally is an implementation design. Even if all current implementations (of the CLI) round it first that doesn't have to be the case in the future.
The problem with your code is actually the first line, where you call FromMilliseconds. As noted previously, the remarks in the documentation state the following:
The value parameter is converted to ticks, and that number of ticks is used to initialize the new TimeSpan. Therefore, value will only be considered accurate to the nearest millisecond.
In reality, this statement is neither correct nor logically sound. In reverse order:
Ticks are defined as "one hundred nanoseconds". By this definition, the documentation should have been written as:
Therefore, value will only be considered accurate to the nearest millisecond tick, or one ten-millionth of a second.
Due to a bug or oversight, the value parameter is not converted directly to ticks prior to initializing the new TimeSpan instance. This can be seen in the reference source for TimeSpan, where the millis value is rounded prior to its conversion to ticks, rather than after. If maximum precision were to be preserved, this line of code should have read as follows (and the adjustment by 0.5 milliseconds 3 lines earlier would be removed):
return new TimeSpan((long)(millis * TicksPerMillisecond));
Summary:
The documentation for the various TimeSpan.From*, with the exception of FromTicks, should be updated to state that the argument is rounded to the nearest millisecond (without including the reference to ticks).
Or, you could do:
double x = 0.4;
TimeSpan t = TimeSpan.FromTicks((long)(TimeSpan.TicksPerMillisecond * x)); // where x can be a double
double ms = t.TotalMilliseconds; //return 0.4
--sarcasm
TimeSpan converts the double of milliseconds to ticks so "OBVIOUSLY" you can have a TimeSpan with less than a 1ms granularity.
-/sarcasm
-- this isn't obvious at all...
why this isn't done inside the .FromMilliseconds method is beyond me.

How to Make Math.Round for a Number

how to make the Rounded number ?
Example : 3341.48 to 3342.00
It seems you always want to round up here. In that case use
Math.Ceiling(3341.48)
This will return 3342.
If you want to round towards the nearest whole number, use
Math.Round(3341.48)
This will return 3341. Note that Bankers roundingis the default setting here, that might cause some unexpected result for rounding X.50.
If you want 3341.48 to round up to 3342, it sounds like you might want Math.Ceiling:
decimal m = 3341.48m;
decimal roundedUp = Math.Ceiling(m);
This will always round up - so 3341.0000001 would still round to 3342, for example. If that's not what you're after, please specify the circumstances in which you want it to round up, and those in which you want it to round down instead.
Note that this will round up to 3342, not 3342.00 - it doesn't preserve the original precision, because you've asked for an integer value by using Math.Ceiling.
It's relatively unusual to then want to force the precision to 2, but you could divide by 100 and then multiply by 100 again, if necessary. Alternatively, if you only need this for output you should look into formatting the result appropriately rather than changing the value.
Use Math.Round(number) if you want to round number to the nearest integer.
Use Math.Round(number,digits) if you want to round number to a specified number of fractional digits.
If you want to round to lower/higer value use Math.Floor(number) / Math.Ceiling(number) instead.
To round monetary amounts to 5 cents:
amount = 20 * int(amount / 20)

Categories

Resources