Issue with float datatype - c#

I have a radnumeric textbox with monthly salary as below.
txtMonthlySalary.Text=816177200
Now I need to calculate the annual salary and save it as a float variable in the sql server table.My table is already an existing one and the annual salary field is type float.
Actual calculation on Annual salary gives following result:
Annual salary = 816177200 * 12 = 9,794,126,400
But in the program,
float Fld_AnnualSalary = float.Parse(txtMonthlySalary.Text) * 12;
gives result as 9,794,127,000
Here float data type rounds the result it seems,which is a big variation from the actual expected result.
How can I handle this issue,so that I can get the exact result on multiplication without rounding and save it in a float variable in sql sever table.

float and even double are not generally acceptable data types to work with real money values (as you just proved for yourself).
Please use Decimal in the code and corresponding type in SQL.

A float has a precision limited to about seven digits, and you are trying to do calculations on a nine-digit number 816177200.
The anwer by Alexeis Levenkov contains the solution to your problem. The Decimal data type can hold at least 28 significant digits.

Related

double or decimal when calculating percent

Based on this thread decimal vs double!, decimal is always used for money. What is the proper way to define percent? like TaxPercent? If it's double then for calculating amount * 8% (double) you would have to cast it.
What's the proper way to define percent value (ie tax) and what would the calculation be.
Use the 'm' suffix to specify a literal as a decimal. So it must be 0.08m to ensure a double doesn't creep into the calculation.
decimal tax = amount * 0.08m;
You'll find a list of valid suffix characters in this post.

Issue with calculating financial values using float in C#

I was reading an article related to difference between Float and double. and they given an example as below :
Say you have a $100 item, and you give a 10% discount. Your prices are all in full dollars, so you use int variables to store prices. Here is what you get:
int fullPrice = 100;
float discount = 0.1F;
Int32 finalPrice = (int)(fullPrice * (1-discount));
Console.WriteLine("The discounted price is ${0}.", finalPrice);
Guess what: the final price is $89, not the expected $90. Your customers will be happy, but you won't. You've given them an extra 1% discount.
In above example, to calculate the final price they have used fullPrice * (1-discount) . why they used (1-disocunt) ? it should be fullPrice * discount.
so my confusion is about logic to calculate the final price. why thay used (1-discount) instead of discount ?
the final price is $89, not the expected $90
That's because when 0.1 is float, it is not exactly 0.1, it's a little more. When you subtract it from 1 to do the math, you get $89.9999998509884. Casting to int truncates the result to 89 (demo).
You can make this work by using decimal data type for your discount. This type can represent 0.1 without a precision loss (demo).
why they used (1-disocunt)
1 represents 100%. The price after discount is (100%-10%)=90%
This question is actually about math.
Let's suggest you have an item which costs 100$.
The seller provides a discount to you - 10%.
Now you need to calculate what is the final price of an item.
I.e., how much money should you give to get it?
The answer: you need to pay the full price of an item minus discounted price.
100% of a cost - 10% discount = 90% final price
That's why it is fullPrice * (1 - discount).
If you calculate it using your formula fullPrice * discount then it will mean that the item which costs 100$ will be sold for 10$ due to 10% discount - which is incorrect. Actually, this formula fullPrice * discount may be used for calculation of discounted amount.
There is nothing wrong with the overall logic of the above example, but it does have very unfortunate choice of data types. This leads to the values being converted implicitly to double, introducing a slight rounding error in the process. By casting back to int, the result is truncated. This greatly amplifies the rounding error.
This is a good example of a problem that frequently occurs when dealing with financial values in programming:
Float values do not tanslate well to decimal fractions.
Most new developers tend to think of float values as decimal fractions, because they are mostly represented by these, when converting them to strings and vice versa. This is not the case. Float values have their fractional part stored as binary fraction, as descibed here.
This makes float values (and their calulations) being slightly askew from their decimal representations. This is why the following results to $89,9999998509884:
double fullPrice = 100;
double discount = 0.1F;
double finalPrice = (fullPrice * (1 - discount));
Console.WriteLine("The discounted price is ${0}.", finalPrice);
(Not so) fun fact: The above will work fine when using float as data type, because the afforementioned error lies below the resolution of single precision values in this example and the assembly code does use double precision behind the scenes. When the result gets converted to single precision, the error gets lost.
One way out of this problem, is to use the data type decimal, that was construced to do calculations that have to translate directly to decimal fractions (as financial calculations do):
decimal fullPrice = 100;
decimal discount = 0.1m;
decimal finalPrice = (fullPrice * (1 - discount));
Console.WriteLine("The discounted price is ${0}.", finalPrice);
Another would be to round all results of floating point calculations, before displaying or storing them. For financial calculations one shoud use:
Math.Round([your value here], 2, MidpointRounding.AwayFromZero);

decimal issue when adding a flat fee

I have a small issue I believe the code is doing exactly what its suppose to be doing I have a function whereby I pass in an amount and I add a flat fee of 40 cents to it for the surcharge.
Below is how my current code is constructed
Double surcharge;
surcharge = 0.4 * moneyIn / 100;
If I pass 999.00m in as moneyIn it returns 0.3996 when in fact it should return 0.4 I'm unsure what I need to do to make it be 0.4.
You're not using decimal - you're using double. Use decimal everywhere (so moneyIn should be a decimal too). If you're actually using 999.00m for moneyIn, that would make it a decimal and your current code wouldn't even compile (as there are no implicit conversions between decimal and double).
Now your code doesn't actually talk about a flat fee of 40 cents - it's taking 0.4% of the original value. You should have something like:
decimal surcharge = 0.40m; // 40 cents
decimal total = moneyIn + surcharge;

C# float variable showing epsilon number

i am facing a problem while assigning a large value to a float variable. Following is the code
float f1=99999999999.959f;
When i am retrieving value from this variable it is showing 1.0E+11 value. i want to get my original value. Can anyone help me to sort-out this problem.
In C#, float values only have a precision of 7 digits, so you're getting the best you can out of that data type. If you need more precision, use double or decimal.
http://msdn.microsoft.com/en-us/library/s1ax56ch.aspx
you are getting back the number you entered, to the degree of accuracy available from a float (about 6-7 d.p.)
So firstly, the storage of the value has limited precision, and secondly the way you display it may add further rounding.
If you use a double, you will increase the precision to around 15 d.p., or you can go further and use a decimal.
Primitives types float and double are approximations.
Here is a great response on their precision: How to Calculate Double + Float Precision
Even decimal has this problem. C# does not come with big num class, but you can use libraries for that. If you need more accurate decimal numbers then decimal (±1.0 × 10^−28 to ±7.9 × 10^28) you should try them.
Example: https://bcl.codeplex.com/ (BigRational)

Using Double data type to transport Money values

I understand that using Double data type for Money calculations is asking for trouble so Decimal should be used instead.
I feel stupid asking this, but could there be potential problems in using the Double data type to just store or transport a Money value, so long as it is converted to a Decimal when doing calculations?
I ask this because I have an old application on my hands to maintain, and it is using Double everywhere. To save work, I would like to only refactor the parts that actually do calculations, to use Decimal instead of Double. I would like to leave the rest of it alone where it is only plumbing code for data-transfer, serialization and such.
There is a loss of precision when you store data in double not just when you retrieve it. So no, this doesn't get around your problem. You can't magically retrieve precision that has been lost.
The answer depends on how many significant digits you need to "transport". Decimal gives you 28 digits while Double gives you about 15 or so. So if your values are in the range +/- 10 trillion (assuming 2 decimal places) you should be OK. If you use other currencies you will probably need more decimal places, so the range will be reduced to e.g. +/- 100 billion with 4 decimal places.
you shouldnt use floating point values to store monetary value..
MAybe use BigDecimal.. https://blogs.oracle.com/CoreJavaTechTips/entry/the_need_for_bigdecimal
For example you are inserting a transaction, assuming that all the calculations are performed using decimal data-type
Amount : $45.35
TAX : $ 1.72
-----------------
Total : $47.07
Now we assume that you make a sales voucher and store all the three values. While storing you convert all the three values to double. So it becomes binary floating values.
If user again tries to open the old sales voucher, you try and retrieve the three values; it may happen due to rounding and conversion (from double to decimal) you receive different values, which may appear as follows
Amount : $45.36 (//changed)
TAX : $ 1.72
-----------------
Total : $47.07 (//Total sum is as stored, but when you sum
//actual values retrieved, they are different.)
This is based on my experience, currently I am unable to technically explain this occurrence.
It may also happen that you store only Amount and Tax Rate but when you add them the total would be 1 cent more that the actual sales voucher which customer has:
Amount : $45.36 /*View after sales*/ Amount : $45.35 /*What customer's*/
TAX : $ 1.72 TAX : $ 1.72 /*voucher says:*/
----------------- -----------------
Total : $47.07 Total : $47.07

Categories