I have a method that calculates the number of minutes between two times. Something like this:
DateTime UserLocalTime = DateTime.UtcNow.ConvertToUserTime(UserTimezoneID);
double TheOffset = (UserLocalTime - DateTime.UtcNow).TotalMinutes;
return TheOffset.ToString();
The problem is that it's returning something like 119.83723 because it's calculating minutes AND seconds and such.
How can I fix this? I'm afraid sometimes it'll also return 120.11233 so rounding might not totally help either.
Thanks for your suggestions.
Update1: (int)(Math.Round((UserLocalTime - DateTime.UtcNow).TotalMinutes)); returns 119.
Update2: I tried this, it looks like it works but will fail when the offset is weird (sometimes it might be 5:30 and the answer should be 330 minutes)
int TheOffset = (int)(Math.Round((UserLocalTime - DateTime.UtcNow).TotalHours));
TheOffset = TheOffset * 60;
Do you want to get only the minutes and nothing else? Just use Minutes instead of TotalMinutes.
Do you want to get the total number of minutes, but not any measure beneath it? Use (int)TotalMinutes. It'll round down.
I'm afraid sometimes it'll also return 120.11233 so rounding might not totally help either.
Can you clarify? Rounding 120.11233 will result in 120... I think that's what you want, right?
You have can use:
Math.Round() to get the nearest integer
Math.Floor() to get the largest integer less than or equal to the specified number.
Math.Ceiling() to get the smallest integral value greater than or equal to the specified number.
119,895 -> Floor= 119, Ceiling = 120, Round = 120
119,175 -> Floor= 119, Ceiling = 120, Round = 119
Apply the desired function to your TheOffset.
If you need Ceiling or Floor, you should probably invert the function used if negative or positive offset.
So, you decide what you want to get.
Related
I'm testing a system which gave 10% of discount in a product, this means 102.555 of discount, but the system only use 2 fractional digits, so it gave 102.55.
The problem is if I execute this:
Math.Round(102.555, 2, MidpointRounding.AwayFromZero)
The output is: 102.56
And if I execute this:
Math.Round(102.555, 2, MidpointRounding.ToEven)
The output is also 102.56.
I was using Math.Round method with all scenarios, until this came up.
What am I doing wrong?
Why is 102.555 returning 102.56 with MidpointRounding.AwayFromZero?
How Can I do something to return 102.55 from 102.555?
Why is 102.555 returning 102.556 with MidpointRounding.AwayFromZero?
I presume "102.556" should read "102.56" here.
Because MidpointRounding indicates what happens when you are rounding a number where the significant digit for rounding (i.e. the last disappearing digit) at radix 10 is 5. This is the case for your number 102.555, so when rounding to two decimal places, there are two options:
102.55
102.56
MidpointRounding.AwayFromZero picks the option that is further away from zero - in this case (as these are positive numbers) the greater one, namely 102.56.
Ok, I found the answer:
https://stackoverflow.com/a/13483693/375422
public double TruncateDown(double number, int decimalPlaces)
{
return Math.Floor(number * Math.Pow(10, decimalPlaces)) / Math.Pow(10, decimalPlaces);
}
public double TruncateUp(double number, int decimalPlaces)
{
return Math.Ceiling(number * Math.Pow(10, decimalPlaces)) / Math.Pow(10, decimalPlaces);
}
In my case, I want to round down.
While string truncation will work, you want the floor() function used this way:
double value = Math.Floor(Math.Int(sourceVal * 100)) / 100;
There are two types of rounding, the banker's rounding (i.e. to even), and everyday rounding (i.e. away from zero).
Simply put, away from zero rounding simply checks the number before the precision specified, and if it is 5 or greater, then it rounds up.
However, to even checks whether it will approach an even number when it rounds up, and if so, then it rounds up. However, it it approaches an odd number, then it won't round up.
Bear in mind, the default method Math.Round(x, y) uses to even implicitly.
To even gives a complimentary correct calculation. See here. 1.5 + 2.5 = 4. If you round each one and sum them up, you will still get 4, however, you will get calculation error if you do the same with away from zero.
var x = Math.Round(1.5, 0) + Math.Round(2.5, 0); // 4
var y = Math.Round(1.5, 0, MidpointRounding.AwayFromZero) + Math.Round(2.5, 0, MidpointRounding.AwayFromZero); // 5!
See here for more info: https://msdn.microsoft.com/en-us/library/system.midpointrounding(v=vs.110).aspx
Edit 1:
Following O. R. Mapper & sgmoore comments, I just realized that the point of bankers rounding is to have the odds of rounding up or down almost equally the same over the course of random numbers.
In away from zero rounding, you end up with 1-4 (four odds) rounding down, and 5-9 rounding up (5 odds).
However, in bankers rounding, 1-4 (four odds) will round down, and 6-9 will round up (4 odds), and then we have 5 that will either round up or down, and when applied to random numbers, the odds of rounding up is almost like the odds of rounding down. And that gives a better chance for more accurate calculation specially when summing up.
You can find out more here: Why does .NET use banker's rounding as default?
Edit 2:
If you want to truncate, you can simply use:
decimal x = 102.555M;
decimal truncated = Math.Truncate(x * 100) / 100; // 102.55;
There is a great system to round to the nearest integer adding half to the number.
For example if you want to round 3.8 to 4, you first add 0.5 (it will bring it to 4.3) and then cut the 0 (using mod or int).
In your sample, you need to add 0.005 and then cut the last digit.
It can be done with toFixed(2) to keep two digits after the dot.
Here you have some console output...
(102.555+.005).toFixed(2)
"102.56"
(102.555).toFixed(2)
"102.56"
toFixed rounds to the nearest number so in this case you don't need to add half but to substract it.
(102.555-.005).toFixed(2)
"102.55"
I have to calculate number of days difference between today and SubmittedDate, but if I the SubmittedDate = today
my Result = 0,430090... Instead of 1
here is my code:
DaysDiff = (today.Subtract(DataUtilities.GetSafeDateTime(financialStatement[SharePoint_Assessment_Fields.SUBMITTEDDATE_FIELD]))).TotalDays,
could you please help me ?
The TotalDays property is a double. It also takes the hours and minutes in account, so that might cause the subtraction of two days get fractions too.
If you want to round that, you could use Math.Round, Math.Ceiling or Math.Floor depending on your needs. Taking your expected outcome, I guess you need to use Ceiling:
double ceiledDays = Math.Ceiling(ts.TotalDays);
Or you could get the Date part of the two dates and calculate with that.
I have a little trouble with Math.Ceiling() in C#.
I call it on the result of a division by a number followed by a multiplication by the same number, e.g. 20 000 / 184 * 184. I would expect that result to be 20 000 but it is 20 001. Are there any possible ways how to avoid this behavior when trying round up value?
Thank you in advance
When running the code you supplied we have the following
twentyThousand/oneEightyFour * oneEightyFour
The answer is 20000.000000000000000000000001
Hence when you do the ceiling we have 20001.
By the following article I think the result is due to in inaccuracy introduced when performing the division , this yields 108.69565217391304347826086957 and as Jon stated
As a very broad rule of thumb, if you end up seeing a very long string representation (ie most of the 28/29 digits are non-zero) then chances are you've got some inaccuracy along the way.
http://csharpindepth.com/Articles/General/Decimal.aspx
As light pointed out in the comments, you shouldn't be getting 20001 at all.
20000 / 184 would yield 108. Which then would give you 19872 when multiplied by 184.
Somewhere you are doing something other than what you posted. Where is Math.Ceiling() even called?
I will say, if the numbers are hard coded, you can put a decimal in the code and it will treat it as such. If you are using variables that represent numbers, be sure they are formatted as some floating point type (decimal,double,float) depending on the accuracy needed.
Console.WriteLine(20000 / 184 * 184); // 19872
Console.WriteLine((20000.0 / 184.0 * 184.0)); // 20000
Are there any possible ways how to avoid this behavior when trying round up value?
In this particular case you can avoid the problem by multiplying first, then dividing:
result = (20000m * 184m) / 184m ;
Since the precision is lost in the division, multiplying first prevents that imprecision form getting exaggerated when you multiply.
I'm stuck with a little issue here, say you have the following code:
int whole = 0;
double decimal = 88.00
whole = decimal / 1.5; //now the answer is 58.66
So here's the issue, explicitly casting a double to an int is easy enough. But if I do this now 'whole' is going to be set to 59. This - is not so good, I want it to be set to the last whole number (being 58).
How do you do this in C#?
To round doubles to integers, you have 4 basic math functions:
Math.Round() - Rounds to the nearest whole number (or user specified number of deciml places), and lets you choose to round middle points up or down.
Math.Floor() - Rounds to the first whole number toward negative infinity.
Math.Ceiling() - Rounds to the first whole number toward positive infinity.
Math.Truncate() - Rounds to the first whole number toward zero.
I think you want either Floor or Truncate. Both round down for positive numbers, but Truncate rounds -3.6 to -3, while Floor rounds it to -4.
Casting to int does the same as truncating, so you can use that if you prefer.
Math.Floor:
whole = (int)Math.Floor(decimal / 1.5);
If you cast double to int, the answer will NOT be 59 -- it will be 58. When casting double to int, the value will be rounded towards zero. So, this is sufficient:
int whole = 0;
double x = 88.00;
whole = (int)(x / 1.5); // whole will be 58
Use Math.Floor if you want to round to the last whole number, and Math.Ceiling if you want to round to the next.
If you need rounding, it's pretty common to use:
whole = (int)(decimal / 1.5 + 0.5);
Without the 0.5, you're truncating, not rounding.
If you have a rounding function in your math libraries, that's good too. Some of these will do the odd/even thing for rounding 0.5 to avoid a little bit of data skew.
This will convert the double value into int:
whole = (int)(decimal / 1.5);
Also, you can use Math.Floor(doubleValue).
Given that I have two floats, a and b, and only care if they are "approximately equal", would something similar to the following work reliably, or would be it still be subject to precision issues?
eg:
Math.Round(a) == Math.Round(b)
Alternatively, is there a way to reliably round them to the nearest integer? If the above doesn't work, then I assume simply doing (int)Math.Round(a) won't be reliable either.
EDIT: I should have predicted I'd get answers like this, but I'm not trying to determine 'closeness' of the two values. Assuming the logic above is sound, will the above work, or is there a chance that I will get something like 3.0 == 3.0001?
Nothing of this kind will work. There is always a sharp boundary when very similar numbers will be rounded to different numbers.
In your first example think of a=0.4999999 and b=0.5000001. Very close but will round to different integers.
Another problem is that if the numbers are large rounding to an integer will have no effect at all. And even very close(relative) numbers will already an absolute difference >1.
If you care about determinism, you're out of luck with float and double. You just can't get those deterministic on .net. Use Decimal.
IF you really want it reliable then you will have to use Decimal instead of float... although that is much slower...
EDIT:
With ((int)Math.Round(a)) == ((int)Math.Round(b)) you avoid the problem 3.0 == 3.0001 BUT all the other pitfalls mentioned your post and in the answers will still apply...
You can complicate the logic to try to make it a bit more reliable (example see below which could be packaged nicely into some method) but it will never be really reliable...
// 1 = near, 2 = nearer, 3 = even nearer, 4 = nearest
int HowNear = 0;
if (((int)Math.Round(a)) == ((int)Math.Round(b)))
HowNear++;
if (((int)Math.Floor(a)) == ((int)Math.Floor(b)))
HowNear++;
if (((int)Math.Ceiling(a)) == ((int)Math.Ceiling(b)))
HowNear++;
if (Math.Round(a) == Math.Round(b))
HowNear++;
The correct way to convert from double/float to integers is:
(int)Math.Round(a)
having done this you will always get whole numbers which can be tested for equality. If you have numbers which you know are going to be virtually whole numbers (e.g. the result of 6.0/3.0) then this will work great. The recommended way of checking two numbers which are doubles/floats are approximately equal is:
Math.Abs(a-b)<tolerance
where tolerance is a double value that determines how similar they should be, for example, if you want them to be within 1 unit of each other you could use a tolerance of 1.0 which would give you similar accuracy to Math.Round and comparing the results, but is well behaved when you get two values which are very close to half way between two integers.
You could use Floor or Ceieling methods right to rounding of the values.
"approximately equal" is your answer actually, a pseudoexample:
double tollerance = 0.03;
if(Math.Abs(a-b)<=tollerance )
// these numbers are equal !
else
//non equal
EDIT
Or if you want to be more "precise":
int aint = (int)(a*100); // 100 is rounding tollerance
int bint = (int)(b*100); // 100 is rounding tollerance
and after
if(Math.Abs(aint -bint )<=tollerance ) // tollerance has to be integer in this case, obviously
// these numbers are equal !
else
//non equal