Using integer instead of decimal - c#

I'm having trouble with a particular homework assignment of mine. It almost seems impossible. The question goes like this...
"In the future, you may work with other programming languages that do not have a type like decimal which supports precise monetary calculations. In those languages, you should perform such calculations using integers. Modify the application to use only integers to calculate the compound interest. Treat all monetary amounts as integral numbers of pennies. Then break the result into its dollars and cents portions by using the division and remainder operations, respectively. Insert a period between the dollars and the cents portions when you display the results."
When I follow the directions and use integers I get these overflow errors before I can even divide anything out. Does anyone have any idea how to make this work? Here's the original code that needs to be modified...
decimal amount; //amount on deposit at end of each year
decimal principal = 1000; //initial amount before interest
double rate = 0.05; //interest rate
//display headers
Console.WriteLine("Year{0,20}", "Amount on deposit");
//calculate amount on deposit for each of ten years
for (int year = 1; year <= 10; year++)
{
//calculate new amount for specified year
amount = principal *
((decimal)Math.Pow(1.0 + rate, year));
//display the year and the amount
Console.WriteLine("{0,4}{1,20:C}", year, amount);
}
This is the code I have so far...
long amount; //amount on deposit at end of each year
long principal = 100000; //initial amount before interest
long rate = 5; //interest rate
long number = 100;
//display headers
Console.WriteLine("Year{0,20}", "Amount on deposit");
//calculate amount on deposit for each of ten years
for (int year = 1; year <= 10; year++)
{
//calculate new amount for specified year
amount = principal *
((long)Math.Pow(100 + rate, year));
amount /= number;
number *= 10;
//display the year and the amount
Console.WriteLine("{0,4}{1,20}", year, amount);
It gets some of the right numbers, but then starts spitting out negative numbers for some reason.

Just to give you a hint:
int amount;
//...some code...
//let's pretend we have an amount of 100.97
amount = (int)(100.97 * 100); // amount = 10097

Math.Pow uses double. It does not use long.
In the following line you are implictly casting your rate and year to double.
amount = principal *
((long)Math.Pow(100 + rate, year));
So you are effectly doing this:
double dRate = (double)(100 + rate);
double dYear = (double)year;
double dPow = Math.Pow(dRate, dYear);
amount = principal * (long)dPow;
If you want your Pow function to really use long then you probably need to write it yourself.

Related

An interest calculation task I'm working on doesn't output the proper results

So I'm currently taking a C# fundamentals course as the entrance stage of a 6 month C# learning program. One of the tasks we have under the "Data Types and Variables" is an interest calculator.
The premise is such: You have a "deposit" that you write in the first line. The deposit has a 5% interest to it. The program needs to output the deposit's value for 3 years, for each year, all at once.
So 100.00, 105.00, 110.25, 115.76. The numbers after the decimal point need to be rounded to 2 digits, as well as "The rules of math for rounding apply here".
double deposit = double.Parse(Console.ReadLine());
double interest = (deposit*5)/100;
double yearOne = deposit + interest;
double yearTwo = yearOne + interest;
double yearThree = yearTwo + interest;
string totalSums = ($"{yearOne:N2}\n{yearTwo:N2}\n{yearThree:N2}\n");
Console.WriteLine( totalSums );
This is the code I've written so far. It SEEMS to work, but it's not as accepted.
If I put the deposit value as 100 (one of the examples), I get this output:
100
105.00
110.00
115.00
I've put the calculation for the interest percentage as double interest = (deposit*5)/100, which checks out if I use an external calculator to test it. But the program doesn't give the right output.
Say if I put 100.23 as the deposit input, I'll get: 105.24, 110.25, 115.26 when I should get 105.24, 110.50, 116.02. However, a round 100.00 doesn't even display the digits after the decimal point, just rounds them down to the whole number.
I thought the problem comes from using double and not decimal due to floating-point precision issues, so I changed everything to decimal. I still get this exact problem. Nothing changes.
I've had other issues that I at least have ideas on where I'm going wrong, but this one has been screwing with me since 3 days. So I resorted to some help here.
Why am I not getting the correct outputs ? Where is my problem coming from ? Is it the math ? Or logic ? Maybe I'm not using the correct method ? I'm at a loss... And the learning resources I've been given don't seem to help me with this issue, too. Like it's the ONLY task that the resources don't help with.
I've also seen other posts about compound interest, but they use arrays and other things that I'm not yet at the point of learning within the program. So code like that isn't gonna pass the automatic tester. I'm not asking for a complete code solving or "cheat" if you will; I just need some guidance on what my issue here is, because I'm clueless at this point.
Your question is about compound interest, not simple interest. Therefore, you need to calculate the new interest every year.
double deposit = double.Parse(Console.ReadLine());
double yearOne = deposit + (deposit * 5)/100;
double yearTwo = yearOne + (yearOne * 5)/100;
double yearThree = yearTwo + (yearTwo * 5)/100;
string totalSums = ($"{yearOne:N2}\n{yearTwo:N2}\n{yearThree:N2}\n");
Console.WriteLine( totalSums );
If you know about loops, you can create a loop over 3 years and update the amount in the account:
static class Program
{
static void Main(string[] args)
{
// set interest rate (fixed)
decimal rate = 5m/100;
// get deposit amount from user
Console.WriteLine("Enter Initial Amount:");
string input = Console.ReadLine();
decimal amount = decimal.Parse(input);
// loop over three years
Console.WriteLine($"{"year"}\t{"amount"}");
for (int year = 1; year <= 3; year++)
{
// calculate interest for the year based on
// current amount in the account
decimal interest = rate * amount;
// deposit interest in account
amount += interest;
Console.WriteLine($"{year}\t{amount:c2}");
}
}
}
with output
Enter Initial Amount:
1000
year amount
1 $1,050.00
2 $1,102.50
3 $1,157.63
you need to recalculate the interest amount each year.
double deposit = double.Parse(Console.ReadLine());
//Use deposit to calculate interest
double yearOneinterest = (deposit*5)/100;
double yearOne = deposit + yearOneinterest;
//Use yearOne amount to calculate interest
double yearTwointerest = (yearOne*5)/100;
double yearTwo = yearOne + yearTwointerest;
//Use yearTwo amount to calculate interest
double yearThreeinterest = (yearTwointerest*5)/100;
double yearThree = yearTwo + yearThreeinterest;
string totalSums = ($"{yearOne:N2}\n{yearTwo:N2}\n{yearThree:N2}\n");
Console.WriteLine( totalSums );

Compound Interest Calculation

I have this C# code which calculate compound interest plus principal amount every year.
static void CompoundInterest(double principal, double interestRate, double years, double annualCompound)
{
var total = 0.0;
for (int t = 1; t < years + 1; t++)
{
total = principal * Math.Pow((1 + interestRate / annualCompound),
(annualCompound * t));
Console.Write("Your Total for Year {0} "
+ "is {1}. \n", t, total);
}
}
When I tested it with
CompoundInterest(1000, 0.05, 3, 12);
and the output is
Your Total for Year 1 is 1051.161897881733.
Your Total for Year 2 is 1104.941335558327.
Your Total for Year 3 is 1161.4722313334678.
How should I round it accurately? Another question is Math.Pow uses double but in financial calculation, we need decimal. How do I fix this? Convert into decimal after Math.Pow?
I made some test by rounding first and converting to decimal and by converting to decimal and then rounding afterword. Both gave the same results.
But from the logic point of view, I would convert first than rounding after words. This way I will have better control of testing what is converted and what is rounded.
For converting there are different answers, but I found this method Convert.ToDecimal is supported by all .net frameworks and cores.
ex. decimal value = Convert.ToDecimal(double_value);
And then you decimal.Round, which some one has asked and got answer here Why does .NET use banker's rounding as default?
Just in case reference to Floating-point numeric types.
You can convert a double to a decimal directly if you'd like
decimal decimalTotal = (decimal)total;
As for rounding, there is a built-in function, Math.Round, that takes a variety of number formats. It has a overload to specify how many decimal points you want.
decimal roundedDecimal = Math.Round(decimalTotal, 2);

Unexpected decimal value behavior

I used to think I understand the difference between decimal and double values, but now I'm not able to justify the behavior of this code snippet.
I need to divide the difference between two decimal numbers in some intervals, for example:
decimal minimum = 0.158;
decimal maximum = 64.0;
decimal delta = (maximum - minimum) / 6; // 10.640333333333333333333333333
Then I create the intervals in reverse order, but the first result is already unexpected:
for (int i = 5; i >= 0; i--)
{
Interval interval = new Interval(minimum + (delta * i), minimum + (delta * (i + 1));
}
{53.359666666666666666666666665, 63.999999999999999999999999998}
I would expect the maximum value to be exactly 64. What am I missing here?
Thank you very much!
EDIT: if I use double instead of decimal it seems to works properly!
You're not missing anything. This is the result of rounding the numbers multiple times internally, i.e. compounding loss of precision. The delta, to begin with, isn't exactly 10.640333333333333333333333333, but the 3s keep repeating endlessly, resulting in a loss of precision when you multiply or divide using this decimal.
Maybe you could do it like this instead:
for (decimal i = maximum; i >= delta; i -= delta)
{
Interval interval = new Interval(i - delta, i);
}
Double has 16 digits precision while Decimal has 29 digits precision. Thus, double is more than likely would round it off than decimal.

Decimals to Integers [duplicate]

This question already has answers here:
Using integer instead of decimal
(2 answers)
Closed 9 years ago.
I'm having trouble with a particular homework assignment of mine. It almost seems impossible. The question goes like this...
"In the future, you may work with other programming languages that do not have a type like decimal which supports precise monetary calculations. In those languages, you should perform such calculations using integers. Modify the application to use only integers to calculate the compound interest. Treat all monetary amounts as integral numbers of pennies. Then break the result into its dollars and cents portions by using the division and remainder operations, respectively. Insert a period between the dollars and the cents portions when you display the results."
When I follow the directions and use integers I get these overflow errors before I can even divide anything out. Does anyone have any idea how to make this work? Here's the original code that needs to be modified...
decimal amount; //amount on deposit at end of each year
decimal principal = 1000; //initial amount before interest
double rate = 0.05; //interest rate
//display headers
Console.WriteLine("Year{0,20}", "Amount on deposit");
//calculate amount on deposit for each of ten years
for (int year = 1; year <= 10; year++)
{
//calculate new amount for specified year
amount = principal *
((decimal)Math.Pow(1.0 + rate, year));
//display the year and the amount
Console.WriteLine("{0,4}{1,20:C}", year, amount);
}
This is the code I have so far...
ulong amount; //amount on deposit at end of each year
ulong principal = 100000; //initial amount before interest
ulong rate = 5; //interest rate
ulong number = 100;
//display headers
Console.WriteLine("Year{0,20}", "Amount on deposit");
//calculate amount on deposit for each of ten years
for (int year = 1; year <= 10; year++)
{
//calculate new amount for specified year
amount = principal *
((ulong)Math.Pow(100 + rate, year));
amount /= number;
number *= 10;
//display the year and the amount
Console.WriteLine("{0,4}{1,20}", year, amount);
It gets some of the right numbers, but then starts spitting out zeros for some reason.
You are changing the values of amount and number each time through the loop, but I don't believe that's what you want to do here. If you remove those assignments and change the parameters in your final Console.WriteLine call, (amount / 100 and amount % 100 will be helpful here) you should be able to get the result you are looking for.
((ulong)Math.Pow(100 + rate, year)) Will grow way too fast 105^10 > ulong.
I think teacher ment for them to keep math.pow as a decimal.
amount = (ulong)(Math.Round(principal *
Math.Pow((number + rate)/100.0, year),0));
//display the year and the amount
Console.WriteLine("{0,4}{1,17}.{2,-2}", year, "$" + (ulong)(amount / number), (ulong)(amount % number));
Question just says variables, not constants :) variables would all still be ulong

Evenly divide a dollar amount (decimal) by an integer

I need to write an accounting routine for a program I am building that will give me an even division of a decimal by an integer. So that for example:
$143.13 / 5 =
28.62
28.62
28.63
28.63
28.63
I have seen the article here: Evenly divide in c#, but it seems like it only works for integer divisions. Any idea of an elegant solution to this problem?
Calculate the amounts one at a time, and subtract each amount from the total to make sure that you always have the correct total left:
decimal total = 143.13m;
int divider = 5;
while (divider > 0) {
decimal amount = Math.Round(total / divider, 2);
Console.WriteLine(amount);
total -= amount;
divider--;
}
result:
28,63
28,62
28,63
28,62
28,63
You can solve this (in cents) without constructing an array:
int a = 100 * amount;
int low_value = a / n;
int high_value = low_value + 1;
int num_highs = a % n;
int num_lows = n - num_highs;
It's easier to deal with cents. I would suggest that instead of 143.13, you divide 14313 into 5 equal parts. Which gives you 2862 and a remainder of 3. You can assign this remainder to the first three parts or any way you like. Finally, convert the cents back to dollars.
Also notice that you will always get a remainder less than the number of parts you want.
First of all, make sure you don't use a floating point number to represent dollars and cents (see other posts for why, but the simple reason is that not all decimal numbers can be represented as floats, e.g., $1.79).
Here's one way of doing it:
decimal total = 143.13m;
int numberOfEntries = 5;
decimal unadjustedEntryAmount = total / numberOfEntries;
decimal leftoverAmount = total - (unadjustedEntryAmount * numberOfEntries);
int numberOfPenniesToDistribute = leftoverAmount * 100;
int numberOfUnadjustedEntries = numberOfEntries - numberOfPenniesToDistribute;
So now you have the unadjusted amounts of 28.62, and then you have to decide how to distribute the remainder. You can either distribute an extra penny to each one starting at the top or at the bottom (looks like you want from the bottom).
for (int i = 0; i < numberOfUnadjustedEntries; i++) {
Console.WriteLine(unadjustedEntryAmount);
}
for (int i = 0; i < numberOfPenniesToDistribute; i++) {
Console.WriteLine(unadjustedEntryAmount + 0.01m);
}
You could also add the entire remainder to the first or last entries. Finally, depending on the accounting needs, you could also create a separate transaction for the remainder.
If you have a float that is guaranteed exactly two digits of precision, what about this (pseudocode):
amount = amount * 100 (convert to cents)
int[] amounts = new int[divisor]
for (i = 0; i < divisor; i++) amounts[i] = amount / divisor
extra = amount % divisor
for (i = 0; i < extra; i++) amounts[i]++
and then do whatever you want with amounts, which are in cents - you could convert back to floats if you absolutely had to, or format as dollars and cents.
If not clear, the point of all this is not just to divide a float value evenly but to divide a monetary amount as evenly as possible, given that cents are an indivisible unit of USD. To the OP: let me know if this isn't what you wanted.
You can use the algorithm in the question you're referencing by multipling by 100, using the integer evenly divide function, and then dividing each of the results by 100 (assuming you only want to handle 2 dp, if you want 3dp multiple by 1000 etc)
It is also possible to use C# iterator generation to make Guffa's answer more convenient:
public static IEnumerable<decimal> Divide(decimal amount, int numBuckets)
{
while(numBuckets > 0)
{
// determine the next amount to return...
var partialAmount = Math.Round(amount / numBuckets, 2);
yield return partialAmount;
// reduce th remaining amount and #buckets
// to account for previously yielded values
amount -= partialAmount;
numBuckets--;
}
}

Categories

Resources