SQLite how to use integer for storing price value - java

I am using real type to save price value in SQLite database but it does not return correctly value. If I save a few values like 1.01 it will return 4.029999999999999.
I have read that best way to save prices in SQLite is to use integer type
But I don't know how to use it.
How to store and retrieve prices in this case?
Here code how I retrieve price now:
Cursor cursor = null;
double totalPrice = 0;
try {
cursor = mDB.rawQuery("select " + Expense.PRICE + " from " + Expense.TABLE_NAME + " where " + " (strftime("
+ dateType + ", " + Expense.DATE + "))" + "= ? ", new String[] { currentDate });
} catch (Exception e) {
Log.e(TAG, "error" + e.toString());
e.printStackTrace();
}
for (cursor.moveToFirst(); !cursor.isAfterLast(); cursor.moveToNext()) {
totalPrice += cursor.getDouble(cursor.getColumnIndex(Expense.PRICE));
}

It is actually quite simple when you see it.
I don't know what currency you are in, but assume US $.
You want to store $1.01. This is the same as 101 cents. You just multiply by 100.
So before storing the number, multiply by 100.
When displaying the number, divide by 100.
Just to add to that answer: I also think you should store the numbers in memory as cents/integers too. So for all your workings, calculations etc, use that integer format.
If a user enters a $ amount, convert it straight away into integer (multiply by 100). And only change back to $ when you need to display it.
In other words, not just when going to and from the database.

Effective Java book describes, in Item 48, that one should not use float or double if exact answers is required.
I think you should use long value to store the price value, but store the values in "cents" (or equivalent as per currency of choice) instead of "dollars". This way your math around prices should work just fine with no loss due to floating-point arithmetic.

Related

Can't remember how to do this for some reason

This one should be fairly simple I think, I just can't remember how, when using get methods of an object, how to pull the highest double out of the pack and put it in the println.
So far I just get every object to print with its percentages. But for the life of me I just can't remember and I know I've done this before.
public void displayBookWithBiggestPercentageMarkup(){
Collection<Book> books = getCollectionOfItems();
Iterator<Book> it = books.iterator();
while(it.hasNext()){
Book b = it.next();
double percent = b.getSuggestedRetailPriceDollars() / b.getManufacturingPriceDollars() * 100.0;
System.out.println("Highest markup is " + percent + " " + b.getTitle() + " " + b.getAuthor().getName().getLastName());
}
}
I'm pretty sure I need another local variable but I can't seem to do anything but make it equal the other percent. I have removed the other variable for now as I try to think about it.
I won't go into a lot of detail because it's homework (well done for being up-front about that, by the way) but here's the key idea: keep track of the largest percentage you've seen so far as your loop runs. That's what you want in your other variable.
Good job posting what you've tried so far. You were on the right track. As you loop through your books, keep a variables continuously updated with the highest percent seen so far and another variable for the associated book. Output the variable at the end outside the loop after iteration is done. Also, don't forget to check the edge case of an empty list of books! Something like this should do the trick:
public void displayBookWithBiggestPercentageMarkup(){
Collection<Book> books = getCollectionOfItems();
if (books.size() == 0) {
return;
}
Iterator<Book> it = books.iterator();
double highestPercent = 0;
Book highestPercentBook = null;
while(it.hasNext()){
Book b = it.next();
double percent = b.getSuggestedRetailPriceDollars() / b.getManufacturingPriceDollars() * 100.0;
if (percent > highestPercent) {
highestPercent = percent;
highestPercentBook = b;
}
}
System.out.println("Highest markup is " + highestPercent
+ " " + highestPercentBook.getTitle()
+ " " + highestPercentBook.getAuthor().getName().getLastName());
}

How to remove duplicates from a parallel array in Java?

So, I started learning Java and was wondering how parallel arrays of string and int type could be stored exactly once from the source arrays. For example, I have two arrays parallel to each other, one stores the Phone number as a string and the other stores the duration of the calls as a/an int gotten from each phone number.
String[] phoneNumbers;
phoneNumbers = new String[100];
int[] callDurations = new int[phoneNumbers.length];
int size = 0;
phoneNumbers[0] = "888-555-0000";
callDurations[0] = 10;
phoneNumbers[1] = "888-555-1234";
callDurations[1] = 26;
phoneNumbers[2] = "888-555-0000";
callDurations[2] = 90;
phoneNumbers[3] = "888-678-8766";
callDurations[3] = 28;
size = 4;
I wrote a method to find the details of a specific phone number, such as the duration of the specific call "888-555-1234"
Here is the method and how I called it:
public static void findAllCalls(String[] phoneNumbers, int[] callDurations, int size, String targetNumber) {
int match;
System.out.println("Calls from " + targetNumber + ":");
match = find(phoneNumbers, size, 0, targetNumber);
while (match >= 0) {
System.out.println(phoneNumbers[match] + " duration: " + callDurations[match] + "s");
match = find(phoneNumbers, size, match + 1, targetNumber);
}
}
System.out.println("\n\nAll calls from number: ");
findAllCalls(phoneNumbers, callDurations, size, "888-555-1234");
The output of this code is:
All calls from number:
Calls from 888-555-1234:
888-555-1234 duration: 26s
888-555-1234 duration: 28s
Process finished with exit code 0
Whereas,the output I want to get instead is:
All calls from number:
Calls from 888-555-1234:
888-555-1234 duration: 54s
Process finished with exit code 0
(26s + 28s)
How is it possible in java to make sure there are no duplicates stored in a parallel array and get total duration for each phone number instead of having them separately in the arrays?
As already stated in the answers before, you can use a map - will avoid duplicates in both phoneNumber and callDuration (Java code to Prevent duplicate <Key,Value> pairs in HashMap/HashTable).
Or, if you want to stick with the String implementation, you can change the logic in the findAllCalls() method.
public static void findAllCalls(String[] phoneNumbers, int[] callDurations, int size, String targetNumber)
{
int match;
System.out.println("Calls from " + targetNumber + ":");
//match = find(phoneNumbers, size, 0, targetNumber);
int i = 0, duration = 0;
while (i<size)
{
if(phoneNumbers[i].equals(targetNumber))
duration+=callDurations[i];
i++;
//System.out.println(phoneNumbers[match] + " duration: " + callDurations[match] + "s");
//match = find(phoneNumbers, size, match + 1, targetNumber);
}
System.out.println(targetNumber+" duration : "+duration+"s");
}
The question was: "How is it possible in java to make sure there are no duplicates stored in a parallel array and get total duration for each phone number instead of having them separately in the arrays?"
The answer is: There is no (inexpensive) way.
Use a hash map instead. Have a look at java.utils.HashMap. A hash map is a concept to store values (of any kind) associated to a specific key. In your case the values would be the durations, the keys would be your phone number. Therefor you should use a String-Integer hash map here.
On insert do the following:
For each phone number-duration pair do:
Is there already an element in the HashMap of the specified key?
No -> Add phone number and duration
Yes ->
Get the duration stored
Add the current duration to the stored duration
Overwrite the existing item with the new duration calculated
Later you efficiently can perform a lookup.
A Map is an object that maps keys to values
In your case, you want phone numbers (stored in a String) to correspond to call duration (ints). Therefore, you'd declare your HashMap as follows (Note you can't instantiate Map, it is an interface):
Map<String, Integer> callRecords = new HashMap<String, Integer>();
This is a better version because you no longer need to keep track of two different arrays. Now, instead of
phoneNumbers[0] = "888-555-0000";
callDurations[0] = 10;
You can write:
callRecords.put("888-555-0000", 10);

Do you have to parse a string to a double every time you want to use it?

I am writing a program where the application has text fields to enter dollar amounts.
There are methods that need to throw exceptions for items such as dollar amounts less than zero. when doing this I have check for exceptions like this:
if (Double.parseDouble(str) <= 0 || Double.parseDouble(str) > 10000)
throw new InvaildDepositAmount("Deposit Amount " + str);
else
totalBalance += amount;
My question is : Do I need to use the Double.parseDouble(str) every time I want to use this input, such in the InvalidDepositAmount class?
The simple answer is no. You can parse it once and use it as a variable later.
double depositAmount = Double.parseDouble(str);
if (depositAmount <= 0 || depositAmount > 10000)
throw new InvaildDepositAmount("Deposit Amount " + depositAmount);
else
totalBalance += depositAmount;
This is also more efficient because, what if the call to parseDouble were expensive (that is, it took a long time for it to get an answer)? Calling it once would be more efficient and easier to read in the long run.
You can just use a variable.
double x = 0;
try {
double x = Double.parseDouble(str);
} catch(Exception ex) {
throw new InvaildDepositAmount("Deposit Amount " + str)
}
if (x <= 0 || x > 10000) {
throw new InvaildDepositAmount("Deposit Amount " + str)
}
I think it makes to code readable, but I'm not sure if it makes it more efficient because the compiler or JVM could notice that and use that expression just once (and do exactly what i'm doing in the code :))
Looks like you have following cases here:
1. input field that should accept only double numbers
2. some functions which accept limited range of double numbers
Obviously you can cache entered value to avoid redundant invocation of Double.parseDouble. Also you should keep that cached value actual and update it if user changed the value in input field.
In case of exceptions related to limits in your functions you can show some popup, or update status line or whatever is suitable for your application. Or probably you want to limit input field about entered value and validate value after each change.

What am I doing wrong here? if statements not adding up

total in this case is 500. Trying to make a calculator, but not everything's adding up. It seems to skip the multiplication and just display total*amount. Is there something I'm doing wrong? EDIT: Discount: in the example, .92. I get 455000 if amount is 1000.
if (wShipping==true){
if (GroundShipping.isSelected()){
if (amount<=99) {
shipping=1.05;
output.setText(output.getText() + amount + "\t" + total*1.05*amount*discount + "\n");
}
else{
output.setText(output.getText() + amount + "\t" + total*amount*discount + "\n");
}
}
if (AirShipping.isSelected()){
shipping=1.1;
output.setText(output.getText() + amount + "\t" + total*amount*1.1*discount + "\n");
}
if (FedexShipping.isSelected()){
shipping=1.25;
output.setText(output.getText() + amount + "\t" + (total*amount*discount)*(1.25) + "\n");
}
}
You should consider the following things--
1) Why is the variable shipping needed if you are directly using the value in the set statement
2) Use else if statement since all the options are exclusive
3) You might want to check the initial values for variables and the formula for calculating the price. Taking the initial values as given, the lowest possible price is-
Price = 1000*500*0.92 = 460000 (total x amount x discount)
Hence there must be something amiss with your initial values
Maybe, just maybe is the first rule of currency calculations:
why not use double or float to represent currency

Comparing data from SQLite database - Android (java)

I made a SQLite highscores that has 3 columns; rank(int), score(long) and percentage(int). I am trying to pull all the data from the columns and compare them to the score the user just got to see if their new score made the highscores list that holds the top 10.
I want the highscores to be prioritized by percentage first and then score to break any ties. Below is where I am starting to do this. Am I on the correct track? I have never used SQLite even outside of Java so this is all brand new to me.
Thank you in advance for your help.
//Check if new record makes the top 10.
public boolean check(int rank, long score, int percentage) {
//SQL query to get last score/percentage if highscores has 10 records...
long[] scores = new long[9];
int[] percentages = new int[9];
scores = db.execSQL("SELECT " + SCORE + " FROM " + TABLE + ";"); //Error: Type mismatch
percentages = db.execSQL("SELECT " + PERCENTAGE + " FROM " + TABLE + ";"); //Error: Type mismatch
//Algorithms to compare scores and percentages go here...
}
scores = db.execSQL("SELECT " + SCORE + " FROM " + TABLE + ";");
execSQL returns void.
As per javadoc
Execute a single SQL statement that is NOT a SELECT or any other SQL statement that returns data.
You may need to use either query (or) rawQuery mechanisms to do select.

Categories