Become a MacRumors Supporter for $50/year with no ads, ability to filter front page stories, and private forums.

gotenks05

macrumors member
Original poster
Jan 1, 2009
78
0
I am trying to work on an Android app, but I am having troubles. The program calculates the age of the person depending on their birth date and current date, then figure the RMD value. The program is accepting the birth date and the balance, because those show up fine, but the RMD value always comes to zero. Now, before you guys go saying "Go somewhere else. We don't deal with Android programming", I have verified that this is a problem in J2SE as well. The age and RMD values are calculated in an external class and when I tested out the external class with a desktop program, it gives me the same results as the Android app, which means the problem is definitely in my external class and it is a Java problem, not an Android platform exclusive problem. How do I fix this, so that the RMD shows the correct results, instead of "0.0"?

Here is the external class source:

Code:
import java.util.*;
import java.text.*;

public class RMD
{
	double balance;
	double rmd;
	long age;
	String bdate;
	SimpleDateFormat sd = new SimpleDateFormat("MM/dd/yyyy");
	
	Date current = new Date();
	public void setBalance(double i)
	{
		balance = i;
	}

	public double getBalance()
	{
		return balance;
	}

	public void setBDate(String h)
	{
		bdate = h;
	}

	public long getAge() throws Exception
	{
		
		Date birthd = sd.parse(bdate);
		long cur;
		long birth;
		long diff;

		cur = current.getTime();
		birth = birthd.getTime();
		diff = cur - birth;
		age = (diff/(24*60*60*1000))/365;
		return age;
	}

	public double getRMD()
	{

		if (age == 70)
		{
			rmd = balance/27.4;
		}

		if (age == 71)
		{
			rmd = balance/26.5;
		}

		if (age == 72)
		{
			rmd = balance/25.6;
		}

		if (age == 73)
		{
			rmd = balance/24.7;
		}

		if (age == 74)
		{
			rmd = balance/23.8;
		}

		return rmd;
	}
}

Yes, I have tried the equals and the compareTo() methods. They either returned the same results or complained that I was trying to dereference a long variable.
 

jared_kipe

macrumors 68030
Dec 8, 2003
2,967
1
Seattle
it appears that the variable "rmd" is only calculated if the age is 70, 71, 72, 73, or 74. Otherwise it is always returned as 0.0 (the starting value).

EDIT: also, the age thing (meaning the multiple if statements) is horrible programming in general. Though I guess if there is really no formula for the conversion you'll be stuck with something similar. But at least use a switch control structure.
 

gotenks05

macrumors member
Original poster
Jan 1, 2009
78
0
it appears that the variable "rmd" is only calculated if the age is 70, 71, 72, 73, or 74. Otherwise it is always returned as 0.0 (the starting value).

EDIT: also, the age thing (meaning the multiple if statements) is horrible programming in general. Though I guess if there is really no formula for the conversion you'll be stuck with something similar. But at least use a switch control structure.

I'll try the switch statement. As for the formula, it depends on the age since there are certain values that the balance must be divided by, as provided by online RMD tables.

Update: I have now implemented a switch control structure the code now looks like this:

Code:
import java.util.*;
import java.text.*;

public class RMD
{
	double balance;
	double rmd;
	long age;
	String bdate;
	SimpleDateFormat sd = new SimpleDateFormat("MM/dd/yyyy");
	
	Date current = new Date();
	public void setBalance(double i)
	{
		balance = i;
	}

	public double getBalance()
	{
		return balance;
	}

	public void setBDate(String h)
	{
		bdate = h;
	}

	public long getAge() throws Exception
	{
		
		Date birthd = sd.parse(bdate);
		long cur;
		long birth;
		long diff;

		cur = current.getTime();
		birth = birthd.getTime();
		diff = cur - birth;
		age = (diff/(24*60*60*1000))/365;
		return age;
	}

	public double getRMD()
	{
		int years = (int)age;

		switch (years)
		{
			case 70: rmd = balance/27.4; break;

			case 71: rmd = balance/26.5; break;

			case 72: rmd = balance/25.6; break;

			case 73: rmd = balance/24.7; break;

			case 74: rmd = balance/23.8; break;
			default: rmd = 0.0; break;
		}

		return rmd;
	}
}

It still gives the same trouble, but this might be better code to read.

Update 2: I found a solution, although it is not exactly what I wanted. I would have like to keep the single method solution, but it did not work out as well as separating the formulas into separate methods for each age. If anyone can provide a solution to that, I'd be grateful.
 
Last edited:

jared_kipe

macrumors 68030
Dec 8, 2003
2,967
1
Seattle
I have no idea what you're talking about. Why is age stored as a long and then cast to an integer "years"?

Why are you only testing these few select years?

Why not put
int years = getAge();
into the getRMD method, since getAge calculates the age itself.
 

gotenks05

macrumors member
Original poster
Jan 1, 2009
78
0
I have no idea what you're talking about. Why is age stored as a long and then cast to an integer "years"?

Why are you only testing these few select years?

Why not put
int years = getAge();
into the getRMD method, since getAge calculates the age itself.

I did it that way since the switch statement only accepts integers. Also, I was only able to use either a long or a double in calculating the age, unless the millisecond values of the dates can be held in an integer, so the age would need to be cast as an integer anyway, since both a double and a long are larger values than an integer.

Also, I was only testing those years, since those were the only ages I had on hand at the time. I looked up the info for all of the other ages and have those, but if the method does not work with that small group, how would it even work with ages 75-115+. Values end at age 115, so everyone older than 115 gets treated like they are 115.

Update: I found the solution. From the information provided by jared_kipe, I used this:

Code:
switch ((int)getAge())

and everything worked.
 
Last edited:

jared_kipe

macrumors 68030
Dec 8, 2003
2,967
1
Seattle
I did it that way since the switch statement only accepts integers. Also, I was only able to use either a long or a double in calculating the age, unless the millisecond values of the dates can be held in an integer, so the age would need to be cast as an integer anyway, since both a double and a long are larger values than an integer.

Umm so they are 70-75 milliseconds old?? Obviously you are NOT storing milliseconds in the age variable so there is no need for it to be a long type.

You do realize why that worked right? The method getAge() is somewhat poorly named as it actually calculates it (and calculates it every time...).

Also, normally getters/setters are named as such:
age()
setAge()
 

lee1210

macrumors 68040
Jan 10, 2005
3,182
3
Dallas, TX
Some notes:
If you want the birthdate as a date, just store it as one. It's wasteful to parse it every time getAge is called.
getAge sets an ivar, but does so every time it's called. Either calculate the age whenever the birthdate is set, and just return it when getAge is called, or get rid of the age ivar, make it local, and rename getAge to calculateAge.
getAge does not get the age in years. Dividing days old by 365 does not give you years old.
I would find another way to grab the denominator for RMD by age in years. Maybe a sparse array, maybe an array with an easily calculated index that you wrap in a function, maybe a Hash, etc. Using a switch here is overkill, and makes adding or changing these values more difficult than it needs to be.
Your current date is initialized when your object is instantiated. If the object lives for a few days your calculations will no longer be current.
Your rmd ivar is like your age ivar. Calculate when you have birthdate and balance available and just return this or rename the method calculateRMD and make the ivar local.

-Lee
 

chown33

Moderator
Staff member
Aug 9, 2009
10,758
8,451
A sea of green
Based on the hand typed constants, the denominator is (90.4 - 0.9*(ageInYears))

Guessing that RMD means "Required Minimum Distribution" regarding an IRA (Independent Retirement Account), I strongly suggest using the IRS-supplied tables and procedures, rather than calculating a figure:
http://www.irs.gov/retirement/article/0,,id=96989,00.html

One of the problems appears to be that the OP doesn't know how to make or use tables. Another problem is that some things are not simply a calculation based on age, but on the year in which one attains a specified age. Furthermore, the specified age is fractional (e.g. 70.5), so a long or int type is unlikely to work correctly.

If this isn't regarding Required Minimum Distributions from an IRA, then ignore the above.
 

gotenks05

macrumors member
Original poster
Jan 1, 2009
78
0
Umm so they are 70-75 milliseconds old?? Obviously you are NOT storing milliseconds in the age variable so there is no need for it to be a long type.

You do realize why that worked right? The method getAge() is somewhat poorly named as it actually calculates it (and calculates it every time...).

Also, normally getters/setters are named as such:
age()
setAge()

Wrong. If you look at this:

Code:
cur = current.getTime();
		birth = birthd.getTime();
		diff = cur - birth;
The dates are in milliseconds, because that is the only way I could find the difference between the two dates with the java.util.Date class. From there, I have to convert it into years by using this:

Code:
age = (diff/(24*60*60*1000))/365;

I could cast that line as an integer, but that does not mean I can take the millisecond value of the current date and the date of birth and make them integers.


Some notes:
If you want the birthdate as a date, just store it as one. It's wasteful to parse it every time getAge is called.
getAge sets an ivar, but does so every time it's called. Either calculate the age whenever the birthdate is set, and just return it when getAge is called, or get rid of the age ivar, make it local, and rename getAge to calculateAge.
getAge does not get the age in years. Dividing days old by 365 does not give you years old.
I would find another way to grab the denominator for RMD by age in years. Maybe a sparse array, maybe an array with an easily calculated index that you wrap in a function, maybe a Hash, etc. Using a switch here is overkill, and makes adding or changing these values more difficult than it needs to be.
Your current date is initialized when your object is instantiated. If the object lives for a few days your calculations will no longer be current.
Your rmd ivar is like your age ivar. Calculate when you have birthdate and balance available and just return this or rename the method calculateRMD and make the ivar local.

-Lee

The only database I can use with Android is SQLite, since the application does not access the web. Besides, I'm not coding this in PHP, or I could use MySQL, which I more familiar with than SQLite. Also the birth date is entered by the user. All user input in GUI, at least in Java can only be obtained as a String, thus required me to parse as a date. I could have stored it as a date, if I used a combo of PHP+MySQL.

Guessing that RMD means "Required Minimum Distribution" regarding an IRA (Independent Retirement Account), I strongly suggest using the IRS-supplied tables and procedures, rather than calculating a figure:
http://www.irs.gov/retirement/article/0,,id=96989,00.html

One of the problems appears to be that the OP doesn't know how to make or use tables. Another problem is that some things are not simply a calculation based on age, but on the year in which one attains a specified age. Furthermore, the specified age is fractional (e.g. 70.5), so a long or int type is unlikely to work correctly.

If this isn't regarding Required Minimum Distributions from an IRA, then ignore the above.

Yes, the person that wanted me to make the application did say that, but the formula still depends on getting the person's age, since the divisor changes according to age. I got the formula from an accountant. Also, all RMD tables start at age 70, even though the specified age is 70.5, as you say. Creating tables in Android is different from normal Java, so even if I did try to make or load a table it would take a bit more research between the Android and J2SE APIs. This thread was to deal with the calculation, which is dealing with a class that can be used on Android and J2SE, which I finally found the solution.
 

jared_kipe

macrumors 68030
Dec 8, 2003
2,967
1
Seattle
Wrong. If you look at this:

Code:
cur = current.getTime();
		birth = birthd.getTime();
		diff = cur - birth;
The dates are in milliseconds, because that is the only way I could find the difference between the two dates with the java.util.Date class. From there, I have to convert it into years by using this:

Code:
age = (diff/(24*60*60*1000))/365;

I could cast that line as an integer, but that does not mean I can take the millisecond value of the current date and the date of birth and make them integers.
Wrong, it is called sarcasm.

You are not storing milliseconds in age, there is no chance of overflow.
 

chown33

Moderator
Staff member
Aug 9, 2009
10,758
8,451
A sea of green
Yes, the person that wanted me to make the application did say that, but the formula still depends on getting the person's age, since the divisor changes according to age. I got the formula from an accountant. Also, all RMD tables start at age 70, even though the specified age is 70.5, as you say.
FWIW, your calculation of age is wrong. There aren't exactly 365 days in a year. You haven't accounted for leap years. This will cause errors for people whose birthdays are in early January, or even into later January if of advanced age.

Creating tables in Android is different from normal Java, so even if I did try to make or load a table it would take a bit more research between the Android and J2SE APIs.
Different in what way? A simple table would be an array of doubles indexed by the age in years (perhaps offset by -70), and initialized with a static initializer. Are you saying that Android doesn't allow static initializers?

My mention of a table was a design point, in the same way that an earlier suggestion of replacing multiple if's with a switch was also a design point. After the design is table-based, you can change how the table gets loaded, e.g. to read a file instead of using a static initializer. But if all the values are compiled in, as both if and switch require, then you always have to edit and recompile in order to change the values.
 
Last edited:

lee1210

macrumors 68040
Jan 10, 2005
3,182
3
Dallas, TX
FWIW, your calculation of age is wrong. There aren't exactly 365 days in a year. You haven't accounted for leap years. This will cause errors for people whose birthdays are in early January, or even into later January if of advanced age.

This is one of the six things I mentioned, only one of which the OP addressed, and they did so based on a misunderstanding.

I am afraid that the OP is approaching a (for-pay?) project on very unstable ground. There seems to be programming (or maybe just OOP?) inexperience as well as being unfamiliar with the language, terminology, and platform.

I don't know what android brings to the table, but there are many things wrong here (many I tried to detail) and if this is intended to be used in production I feel for the end user.

To the OP: everyone here is trying to help you and some of your responses have been defensive or combative. Forget about PHP and mySQL. If you don't know enough about Java, its APIs, and your database backend, you should take a few steps back and study these (as well as OOP concepts in general) before diving headlong into a project for a customer. We will be happy to help along the way.

-Lee
 
Register on MacRumors! This sidebar will go away, and you'll see fewer ads.