I've got this line of code:
int WStoneCost = PriceMethod.StoneCost / 100 * AP;
While PriceMethod.StoneCost is equal to 25 and AP is equal to 70.
I've checked it using breakpoints and I can't understand why do I get zero after I run this line. (WStoneCost is equal to zero)
Is it just a wrong symbol or am I doing something wrong? Thanks in advance.
And how to get a correct double at the end? Like 17.5
You are doing integer division, so 25/100 is 0, not 0.25, and hence 0 * 70 is 0. Since your result variable is also an int it's unclear what result you are expecting, but you could reorder the operations to get a non-zero answer:
int WStoneCost = (PriceMethod.StoneCost * AP)/ 100 ;
It's still integer division, but with your inputs will divide 25*70 (1,750) by 100, which will give you 17.
If you want a floating-point decimal result, just use 100m:
decimal WStoneCost = (PriceMethod.StoneCost * AP)/ 100m ;
Since the literal 100m is a decimal, then the compiler will use floating-point decimal division, which will give you a decimal result.
And how to get a correct double at the end? Like 17.5
Your question and both of the two answers given so far indicate that all three of you want to do something dangerously wrong. You are doing financial calculations so you should always be using decimal, never double. double is for physics calculations, not financial calculations.
I agree with JonathanWood. According to the values that you provided, your answer is going to produce a fractional number. Therefore, you need WStoneCost to be a double or a float. Also, you might want to use partentheses in your equations to ensure that the order of operations is carried out to your expectations.
Hope this helps!
-Gary The Bard
Related
When I make a division in C#, it automaticaly rounds down. See this example:
double i;
i = 200 / 3;
Messagebox.Show(i.ToString());
This shows me a messagebox containing "66". 200 / 3 is actually 66.66666~ however.
Is there a way I can avoid this rounding down and keep a number like 66.6666667?
i = 200 / 3 is performing integer division.
Try either:
i = (double)200 / 3
or
i = 200.0 / 3
or
i = 200d / 3
Declaring one of the constants as a double will cause the double division operator to be used.
200/3 is integer division, resulting in an integer.
try 200.0/3.0
200 / 3 this is an integer division. Change to: 200.0 / 3 to make it a floating point division.
You can specify format string with the desired number of decimal ponits:
double i;
i = 200 / 3.0;
Messagebox.Show(i.ToString("F6"));
Though the answer is actually 66.666, what is happening is that 200 / 3 is being calculated resulting in an integer. The integer is then being placed in the float. The math itself is happening as integer math. To make it a float, use 200.0 / 3. The .0 will cause it to treat 200 as a float, resulting in floating point math.
Aside from the double vs int happening in that action, you're thinking of double as a precise unit. Try using the decimal datatype when you really care about accuracy.
More information at this answer:
decimal vs double! - Which one should I use and when?
double i = 200.0 / 3;
double i = ((double)200)/3;
What happens is the two integers perform an integer divide, and then the integer answer is assigned to the float. To avoid that, always cast one of the numbers as a double.
Try this
i = 200d/3d;
and it will not round.
200 and 3 are both integers, so the result will be an integer. Convert one of them to a decimal.
All given answers are wrong because they translate the integer division into one of kind double, which is cleanly not what was asked for (at least from a performance standpoint). The obvious answer is elementary school math, multiply by 10, add 5 and divide again, all integer.
i = (2000 / 3 + 5 ) / 10
You are catching a second division here, which is better than doing double conversions but still far from perfect. You could go even further and multiply by another factor and add other values than five, thus allowing you to use right shifting instead of dividing by 10. The exact formula for doing this is left as an exercise to the reader. (Just google "divisions with Multiply Shift")
Have a nice day.
I shouldn't get the negative numbers, see the screenshot below:
See the pic below:
Here is the code:
for (double i=8.0; i<=12;i=i+0.5)
{
double aa= (i - Convert.ToInt32(i)) ;
Console.WriteLine(" "+i+" "+aa);
}
If you check the documentation:
Return Value
Type: System.Int32
value, rounded to the nearest 32-bit signed integer. If value is halfway between two whole numbers, the even number is returned; that is, 4.5 is converted to 4, and 5.5 is converted to 6.
This means that every other number will round up, and then down, then up, and then down, which means you'll get negative numbers half the time.
The purpose of this method is to even out bias introduced by always rounding in a particular direction. Consider summing up a huge number of values, rounding them each first. If you always round up, the final sum will always be larger than summing the un-rounded values and then rounding the sum. However, if you round half up and half down according to the rule laid out above, the final sum of the rounded numbers is more likely to be closer to a rounded sum.
You can also read more about this on wikipedia: Round. It is sometimes called bankers rounding although as far as I know banks doesn't use this method.
To ensure you're rounding as you want to:
Down: Math.Floor(Double)
Up: Math.Ceiling(Double)
Even/AwayFromZero: Math.Round(Double, MidpointRounding)
I don't know what you would expect, but double is rounded in this case, not truncated
value: rounded to the nearest 32-bit signed integer. If value is halfway between two whole numbers, the even number is returned; that is, 4.5 is converted to 4, and 5.5 is converted to 6.
Check Convert.ToInt32(double) documentation
try this solve your problem negative marks
for (double i = 8.0; i <= 12; i = i + 0.5)
{
double aa = Convert.ToInt32(i);
Console.WriteLine(aa+" " +i );
}
double aa= (i - Convert.ToInt32(i)) ;
looks like it's alternatively rounding up and down.
Not particularly surprising
When I make a division in C#, it automaticaly rounds down. See this example:
double i;
i = 200 / 3;
Messagebox.Show(i.ToString());
This shows me a messagebox containing "66". 200 / 3 is actually 66.66666~ however.
Is there a way I can avoid this rounding down and keep a number like 66.6666667?
i = 200 / 3 is performing integer division.
Try either:
i = (double)200 / 3
or
i = 200.0 / 3
or
i = 200d / 3
Declaring one of the constants as a double will cause the double division operator to be used.
200/3 is integer division, resulting in an integer.
try 200.0/3.0
200 / 3 this is an integer division. Change to: 200.0 / 3 to make it a floating point division.
You can specify format string with the desired number of decimal ponits:
double i;
i = 200 / 3.0;
Messagebox.Show(i.ToString("F6"));
Though the answer is actually 66.666, what is happening is that 200 / 3 is being calculated resulting in an integer. The integer is then being placed in the float. The math itself is happening as integer math. To make it a float, use 200.0 / 3. The .0 will cause it to treat 200 as a float, resulting in floating point math.
Aside from the double vs int happening in that action, you're thinking of double as a precise unit. Try using the decimal datatype when you really care about accuracy.
More information at this answer:
decimal vs double! - Which one should I use and when?
double i = 200.0 / 3;
double i = ((double)200)/3;
What happens is the two integers perform an integer divide, and then the integer answer is assigned to the float. To avoid that, always cast one of the numbers as a double.
Try this
i = 200d/3d;
and it will not round.
200 and 3 are both integers, so the result will be an integer. Convert one of them to a decimal.
All given answers are wrong because they translate the integer division into one of kind double, which is cleanly not what was asked for (at least from a performance standpoint). The obvious answer is elementary school math, multiply by 10, add 5 and divide again, all integer.
i = (2000 / 3 + 5 ) / 10
You are catching a second division here, which is better than doing double conversions but still far from perfect. You could go even further and multiply by another factor and add other values than five, thus allowing you to use right shifting instead of dividing by 10. The exact formula for doing this is left as an exercise to the reader. (Just google "divisions with Multiply Shift")
Have a nice day.
This is what I am doing, which works 99.999% of the time:
((int)(customerBatch.Amount * 100.0)).ToString()
The Amount value is a double. I am trying to write the value out in pennies to a text file for transport to a server for processing. The Amount is never more than 2 digits of precision.
If you use 580.55 for the Amount, this line of code returns 58054 as the string value.
This code runs on a web server in 64-bit.
Any ideas?
You should really use decimal for money calculations.
((int)(580.55m * 100.0m)).ToString().Dump();
You could use decimal values for accurate calculations. Double is floating point number which is not guaranteed to be precise during calculations.
I'm guessing that 580.55 is getting converted to 58054.99999999999999999999999999..., in which case int will round it down to 58054. You may want to write your own function that converts your amount to a int with some sort of rounding or threshold to make this not happen.
Try
((int)(Math.Round(customerBatch.Amount * 100.0))).ToString()
You really should not be using a double value to represent currency, due to rounding errors such as this.
Instead you might consider using integral values to represent monetary amounts, so that they are represented exactly. To represent decimals you can use a similar trick of storing 580.55 as the value 58055.
no, multiplying does not introduce rounding errors
but not all values can by represented by floating point numbers.
x.55 is one of them )
Decimal has more precision than a double. Give decimal a try.
http://msdn.microsoft.com/en-us/library/364x0z75%28VS.80%29.aspx
My suggestion would be to store the value as the integer number of pennies and take dollars_part = pennies / 100 and cents_part = pennies % 100. This will completely avoid rounding errors.
Edit: when I wrote this post, I did not see that you could not change the number format. The best answer is probably using the round method as others have suggested.
EDIT 2: As others have pointed out, it would be best to use some sort of fixed point decimal variable. This is better than my original solution because it would store the information about the location of the decimal point in the value where it belongs instead of in the code.
The following code in C# (.Net 3.5 SP1) is an infinite loop on my machine:
for (float i = 0; i < float.MaxValue; i++) ;
It reached the number 16777216.0 and 16777216.0 + 1 is evaluates to 16777216.0. Yet at this point: i + 1 != i.
This is some craziness.
I realize there is some inaccuracy in how floating point numbers are stored. And I've read that whole numbers greater 2^24 than cannot be properly stored as a float.
Still the code above, should be valid in C# even if the number cannot be properly represented.
Why does it not work?
You can get the same to happen for double but it takes a very long time. 9007199254740992.0 is the limit for double.
Right, so the issue is that in order to add one to the float, it would have to become
16777217.0
It just so happens that this is at a boundary for the radix and cannot be represented exactly as a float. (The next highest value available is 16777218.0)
So, it rounds to the nearest representable float
16777216.0
Let me put it this way:
Since you have a floating amount of precision, you have to increment up by a higher-and-higher number.
EDIT:
Ok, this is a little bit difficult to explain, but try this:
float f = float.MaxValue;
f -= 1.0f;
Debug.Assert(f == float.MaxValue);
This will run just fine, because at that value, in order to represent a difference of 1.0f, you would need over 128 bits of precision. A float has only 32 bits.
EDIT2
By my calculations, at least 128 binary digits unsigned would be necessary.
log(3.40282347E+38) * log(10) / log(2) = 128
As a solution to your problem, you could loop through two 128 bit numbers. However, this will take at least a decade to complete.
Imagine for example that a floating point number is represented by up to 2 significant decimal digits, plus an exponent: in that case, you could count from 0 to 99 exactly. The next would be 100, but because you can only have 2 significant digits that would be stored as "1.0 times 10 to the power of 2". Adding one to that would be ... what?
At best, it would be 101 as an intermediate result, which would actually be stored (via a rounding error which discards the insignificant 3rd digit) as "1.0 times 10 to the power of 2" again.
To understand what's going wrong you're going to have to read the IEEE standard on floating point
Let's examine the structure of a floating point number for a second:
A floating point number is broken into two parts (ok 3, but ignore the sign bit for a second).
You have a exponent and a mantissa. Like so:
smmmmmmmmeeeeeee
Note: that is not acurate to the number of bits, but it gives you a general idea of what's happening.
To figure out what number you have we do the following calculation:
mmmmmm * 2^(eeeeee) * (-1)^s
So what is float.MaxValue going to be? Well you're going to have the largest possible mantissa and the largest possible exponent. Let's pretend this looks something like:
01111111111111111
in actuality we define NAN and +-INF and a couple other conventions, but ignore them for a second because they're not relevant to your question.
So, what happens when you have 9.9999*2^99 + 1? Well, you do not have enough significant figures to add 1. As a result it gets rounded down to the same number. In the case of single floating point precision the point at which +1 starts to get rounded down happens to be 16777216.0
It has nothing to do with overflow, or being near the max value. The float value for 16777216.0 has a binary representation of 16777216. You then increment it by 1, so it should be 16777217.0, except that the binary representation of 16777217.0 is 16777216!!! So it doesn't actually get incremented or at least the increment doesn't do what you expect.
Here is a class written by Jon Skeet that illustrates this:
DoubleConverter.cs
Try this code with it:
double d1 = 16777217.0;
Console.WriteLine(DoubleConverter.ToExactString(d1));
float f1 = 16777216.0f;
Console.WriteLine(DoubleConverter.ToExactString(f1));
float f2 = 16777217.0f;
Console.WriteLine(DoubleConverter.ToExactString(f2));
Notice how the internal representation of 16777216.0 is the same 16777217.0!!
The iteration when i approaches float.MaxValue has i just below this value. The next iteration adds to i, but it can't hold a number bigger than float.MaxValue. Thus it holds a value much smaller, and begins the loop again.