Can casting cause minute discrepancies in value? - c#

I'm currently writing the Change Return Program on The Big List of Projects and I encountered a logic error in my code. Here is the snippet in question:
if(change / 1 >= 1) // checks if when divided the value is higher than 1, signaling that there is at least a dollar in change
{
double temp1 = change % 1; // declared as double for casting
temp1 = change - temp1; // and used to remove excess, non-dollar value
dollarNum = (int) temp1;
change -= (double)dollarNum;
}
Where change is a double that before this has a value of 10.01. However, after this snippet runs, the value becomes 0.00999999999999979, rather than 0.01 as I want it. Am I assuming something is wrong with casting here? Or is it something else entirely?
Also, note that I tried reformatting the last line to "change = change - dollarNum and tried swapping out dollarNum with temp1 to avoid casting in that line, but neither fixed the issue.
If I formatted anything wrong please let me know and I'll surely fix it as soon as I can.

A double is not suitable for this kind of calculation because it does not store the value exactly (internally it uses binary fractions instead of decimal ones).
Use 'the 'decimal' type instead (https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/decimal):
decimal change = 10.1M;
if(change / 1 >= 1) //checks if when divided the value is higher than 1, signalling that there is at least a dollar in change
{
decimal temp1 = change % 1; //declared as double for casting
temp1 = change - temp1; //and used to remove excess, non-dollar value
int dollarNum = (int)temp1;
change -= (decimal)dollarNum;
}

Related

C# Mathemathics

I wanted to ask a question about a calculation I had today in C#.
double expenses = (pricePen + priceMark + priceLitres) - discount / 100*(pricePen + priceMark + priceLitres); //Incorrect
double expenses = (pricePen + priceMark + priceLitres) - (pricePen + priceMark + priceLitres)* discount/100; //Correct
So as you can see at the end of the equation I had to multiply the brackets by the integer named "discount", which is obviously a discount percentage.
When I change the places of that value whether it would be in front of the brackets or behind the brackets the answer will always be different, but in Maths I even checked myself that I should get the same answer even if the value is placed in front of the brackets to multiply or placed behind the brackets to multiply again, but C# doesn't think so.
I wanted to ask people, how does C# actually calculate this and why am I getting different results at the end? (Result should be 28.5, not 38)
[Data: pricePen = 11.6; priceMark = 21.6; priceLitres = 4.8; discount = 25;]
(I know that the question is irrelevant.)
In first line after dividing by 100 the result is in an integer. For that the rest of division get lost. So the multiplication has a lower result.
In second line the multiplication has the correct result and the rest of devision is lower than one.
So I know its already answered but if you want to learn more about divisions with int
here it is:
for example:
float value = 3/4 you would expect it to be 0.75 but that's not the case.
Because when the Compiler goes through the values 3 and 4 he makes des Literal of the highest data type - in this case (int)-.
That means the result of this division will be "0".75 because int has no floating numbers and just cuts it off. Then the program just takes that value and puts it in the float value ...
so the result will be
"3/4" 0 ->"float value" 0.0 = 0.0
Some guys before me already told you the solution to that problem like making one divisor to float with .0
float value = 3.0/4
or you can tell the Compiler to store the value in a float Literal with the (float) "command"
float value = (float) 3/4
I hope it helped you explain why you did that :)
To avoid these problems makes sure you are doing math with floating point types, and not int types. In your case discount is an int and thus
x * (discount / 100) = x * <integer>
Best to define a function to do the calculation which forces the type
double DiscountedPrice(double price, double discount)
{
return price - (discount/100) * price;
}
and then call it as
var x = DiscountedPrice( pricePen + priceMark + priceLitres, 15);
In the above scenario, the compiler will force the integer 15 to be converted into an double as a widening conversion (double has more digits than integer).

Variable assignment of Double.NaN turns to Double.NegativeInfinity

i've stumbled about a strange bug in my application, when I attached the visual studio debugger.
Here is the code snippet of what I want to talk about:
double lowerLimit = valueProvider.LowerLimit.Value; //valueProvider.LowerLimit.Value = Double.NaN
double upperLimit = valueProvider.UpperLimit.Value; //valueProvider.LowerLimit.Value = Double.NaN
if (Double.IsNaN(upperLimit))
{
var value = StaticClass.DeviceA.GetValue();
upperLimit = value + 0.2;
lowerLimit = value - 0.2;
}
I want to assign the two variables "lowerLimit" and "upperLimit" from the values of the object "valueProvider". The object valueProvider has been deserialized from XML before. Both values of the valueProvider object are Double.NaN. So my variables "lowerLimit" and "upperLimit" will be Double.NaN too, right? Thats right, but sometimes, they will change to Double.NegativeInfinity. Therefore, my logic below won't be executed.
So it looks like this:
double lowerLimit = valueProvider.LowerLimit.Value; //valueProvider.LowerLimit.Value = Double.NaN
double upperLimit = valueProvider.UpperLimit.Value; //valueProvider.LowerLimit.Value = Double.NaN
//lowerLimit = -Infinity
//upperLimit = -Infinity
Actually, this bug happens in under 1% of the executions of this code. I'm pretty sure, that I do not modify these values somewhere else. I've took a look into the Double class and found this declaration for the constants NaN, -Infinity and +Infinity:
public const Double NegativeInfinity = -1D / 0D;
public const Double PositiveInfinity = 1D / 0D;
public const Double NaN = 0D / 0D;
So my questions are:
The mentioned constants seems to be calculated. Is there a chance, that the processor can mess this up?
Is there even a chance that this simple variable assignment can go wrong?
Is there a better way to represent NaN?
Edit: There is only one change where the values are changed. This was in the hidden logic, I've added it. The object of "DeviceA" comes from another library out of my control. If it returns -Infinity it will keep -Infinity, so I would have to search there. Thanks for your help!
NaN is a result of an expression 0/0. PositiveInfinity and NegativeInfinity are the result of expressions such as 1/0 or -1/0. So, there is no better way to represent NaN.
In Javascript, parsing a string will result in NaN. However in C# it will result in an exception with Float.Parse().
To answer your questions:
The mentioned constants seems to be calculated. Is there a chance, that the processor can mess this up? No
Is there even a chance that this simple variable assignment can go wrong? No
Is there a better way to represent NaN? No.

How to extract N number of decimal point without round off?

I want to extract N number of decimal points after the value without doing round up.
Below is the example :
string val = null;
int numberOfDigitsAfterDecimalPoint = 2;
double val1 = 56423747.61;
double val2 = 56423996.57;
val = ((56423747.61 / 56423996.57) * 100).ToString(); //99.9995587692912
val = String.Format("{0:n" + numberOfDigitsAfterDecimalPoint.ToString() + "}", (100 * Convert.ToDecimal(val)) / 100); //100.00
But problem here is it is rounding up and I am getting 100.00 which I don't want because I want exact value with decimal point i.e 99.99 without any kind of round up.
I searched and came to conclusion(my thinking) that best way to handle this is by extracting number of digits after decimal point with substring method but still I am not sure that whether i am thinking in wrong or right way.
Expected output with numberOfDigitsAfterDecimalPoint = 2 :
99.99
Update
I am not having a fixed value to get after decimal point because it is dependent on numberOfDigitsAfterDecimalPoint variable. Apart from that can have very large value based on which I am calculating val; that is why I was thinking to use substring function in which I won't have any problem related to round off, as oppose to mathematical calculation or math function.
How can I do this in efficient way without compromising any value?

Properly round financial data

I decided to re-create my question:
decimal dTotal = 0m;
foreach (DictionaryEntry item in _totals)
{
if (!string.IsNullOrEmpty(item.Value.ToString()))
{
dTotal += Convert.ToDecimal(item.Value);
}
}
Console.WriteLine(dTotal / 3600m);
Console.WriteLine(decimal.Round(dTotal / 3600m, 2));
Console.WriteLine(decimal.Divide(dTotal, 3600m));
The above code returns:
579.99722222222222222222222222
580.00
579.99722222222222222222222222
So, that is where my issues are coming from, I really need it to just display the 579.99; but any round, be it decimal.Round or Math.Round still return 580; even the string formats for {0:F} return 580.00.
How can i properly do this?
New answer (to new question)
Okay, so you've got a value of 579.99722222222222222222222222 - and you're asking that to be rounded to two decimal places. Isn't 580.00 the natural answer? It's closer to the original value than 579.99 is. It sounds like you essentially want flooring behaviour, but with a given number of digits. For that, you can use:
var floored = Math.Floor(original * 100) / 100;
In this case, you can do both in one step:
var hours = Math.Floor(dTotal / 36) / 100;
... which is equivalent to
var hours = Math.Floor((dTotal / 3600) * 100) / 100;
Original answer (to original question)
Sounds like you've probably got payTotal in an inappropriate form to start with:
using System;
class Test
{
static void Main()
{
decimal pay = 2087975.7m;
decimal time = pay / 3600;
Console.WriteLine(time); // Prints 579.99325
}
}
This is the problem:
var payTotal = 2087975.7;
That's assigning payTotal to a double variable. The value you've actually got is 2087975.69999999995343387126922607421875, which isn't what you wanted. Any time you find yourself casting from double to decimal or vice versa, you should be worried: chances are you've used the wrong type somewhere. Currency values should absolutely be stored in decimal rather than double (and there are various other Stack Overflow questions talking about when to use which).
See my two articles on floating point for more info:
Binary floating point in .NET
Decimal floating point in .NET
(Once you've got correct results, formatting them is a different matter of course, but that shouldn't be too bad...)

input string is not in a correct format

I want to calculate the percentage. But the compiler is giving an error that the input string is not in a correct format. Can some one elaborate what i am missing here?
private double per()
{
double a = Convert.ToDouble(tbEnglish.Text+tbUrdu.Text+tbPhysics.Text+tbChemistry.Text+tbMaths.Text);
double d = 500;
double lblResult = (a / d)*100;
return lblResult;
}
You're concatenating the strings and then trying to convert that one result into a double. So for results of 75.6, 92.1, 56.3 78.2 and 72.3 you'd end up trying to parse "75.692.156.378.272.3".
Parse each value and then sum them.
However, I would strongly recommend that you use decimal for this instead of double. You should also consider using TryParse instead of Parse so that you can handle user input errors gracefully. Here's the solution sticking with Parse:
public decimal AveragePercentage()
{
decimal sum = decimal.Parse(tbEnglish.Text) +
decimal.Parse(tbUrdu.Text) +
decimal.Parse(tbPhysics.Text) +
decimal.Parse(tbChemistry.Text) +
decimal.Parse(tbMaths.Text);
return sum / 5m;
}
Out of interest, in your original code why are you dividing by 500 and then multiplying by 100? Why not just divide by 5 (as mine does now that I've noticed what was going on)?
As a side note, it's very important to differentiate between compile-time errors and execution-time errors. It wasn't the compiler saying that the input string wasn't in the correct format - it was the Convert.ToDouble method, at execution time. In this case it was relatively obvious, but in other situations we could have been chasing our tails for a while trying to find a compile-time problem when it was actually failing at execution time.
I don't have Visual Studio available to me here on my Linux box, but I think you're better off with code like this.
private double per()
{
double a = Convert.ToDouble(tbEnglish.Text);
a += Convert.ToDouble(tbPhysics.Text);
a += Convert.ToDouble(tbChemistry.Text);
a += Convert.ToDouble(tbMaths.Text);
double d = 500;
double lblResult = (a / d)*100;
return lblResult;
}
In your example, you end up building a string that will look like: "75.692.156.372.3", which cannot be parsed into a double.
You need to convert all the TextBox.Text values into Decimals before using the + operator.

Categories

Resources