Converting volume (gallons) to mass (grams) using jscience? - java

I can't seem to find/remember a specific formula to convert units of volume to units of mass. I think it has to do with density, but how would this be done?
In my case, I'm trying to write a program using the JScience library to convert any type of unit the user might input into the standard SI.GRAM unit.
The problem comes in with trying to describe things like honey, which are commonly measure in gallons, grams, pounds, and ounces.
I have the following code mostly working when working with units of mass, but I get a ConversionException when trying to work with gallons, which is understandable, since it's measuring volume and not mass.
javax.measure.converter.ConversionException: gal is not compatible with g
Here's what I've got so far. Also, I chose to break up the Amount<Mass> into amount_value and amount_unit because I want to store this in an SQLite database and also have it be represented as text, so I am storing it like this for serialization purposes.
public class Sugar {
private String type;
private double amount_value;
private String amount_unit;
public Sugar(SUGAR_TYPES type, Amount<Mass> amount) {
this.type = type.toString();
this.amount_value = amount.getEstimatedValue();
this.amount_unit = amount.getUnit().toString();
}
public Amount<Mass> getAmount() {
BaseUnit<Mass> mass_unit = new BaseUnit<>(amount_unit);
return Amount.valueOf(amount_value, mass_unit);
}
public SUGAR_TYPES getType() {
return (type != null) ? SUGAR_TYPES.valueOf(type) : null;
}
public double getAmountInGrams() {
Amount<Mass> mass_unit = getAmount();
switch (mass_unit.getUnit().toString().toLowerCase()) {
case "g":
return mass_unit.getEstimatedValue();
case "gal":
// this throws the ConversionException
return NonSI.GALLON_LIQUID_US.getConverterTo(SI.GRAM).convert(mass_unit.getEstimatedValue());
case "lb":
return NonSI.POUND.getConverterTo(SI.GRAM).convert(mass_unit.getEstimatedValue());
default:
Log.e(TAG, String.format("Failed to get Amount<Mass> in SI.GRAM for amount %s and unit %s.",
amount_value, amount_unit));
throw new IllegalArgumentException(mass_unit.getUnit().toString());
}
}
public enum SUGAR_TYPES {
HONEY, SUCROSE, APPLES, APRICOTS, APRICOTS_DRIED, BANANAS, BLACKBERRY, BLUEBERRY,
BOYSENBERRY, CANTALOUPE, CELERY, CHERRY_DARK_SWEET, CRANBERRY, CURRANT_BLACK, DATES,
DATES_DRIED, DEWBERRY, ELDERBERRY, FIGS, FIGS_DRIED, GOOSEBERRY, GRAPE_CONCORD,
GRAPES, GRAPEFRUIT, GUANABANA, GUAVAS, HONEYDEW_MELON, JACKFRUIT, KIWIS, LEMON_JUICE,
LITCHI, LOGANBERRY, MANGOS, MAPLE_SYRUP, PLUMS, RAISINS_DRIED, RASPBERRY_BLACK,
RASPBERRY_RED, RHUBARB, STRAWBERRY, TANGERINES, WATERMELONS
}
}
Is there a better way of doing this? I have other classes that need to have a similar way of converting a generic unit into the SI unit.

You will need mass per volume values for everything you want to calculate. For example, you could expand your enum to include a gram per litre (or kg per m^3, whatever works best for you). You cannot just convert volume to weight without this information:
Example: 1 litre of water=1kg, but 1 litre of petrol=0.88 kg.
Then you only need to convert input volume to your default volume, look up the type, multiply the converted volume with your saved gram per litre and return the result.

Related

How to create a large scale money conversion algorithm in java

I was just trying to create this small android app in android studio to convert currency.
I used 2 Spinner objects to hold only 3 values (USD, POUND, EURO) :
if(actualType.equals("USD")){
if(wantedType.equals("POUND")){
montantConv = montantNonConv * 0.87;
}
else if(wantedType.equals("EURO")){
montantConv = montantNonConv;
}
}
else if(actualType.equals("POUND")){
if(wantedType.equals("EURO")){
montantConv = montantNonConv * 1.15;
}
else if(wantedType.equals("USD")){
montantConv = montantNonConv * 1.15;
}
}
else if(actualType.equals("EURO")){
if(wantedType.equals("USD")){
montantConv = montantNonConv * 1;
}
else if(wantedType.equals("POUND")){
montantConv = montantNonConv * 0.87;
}
}
With if-else the code is too long for a combination of only 3 choices (input + output).
i was just wondering is there a better algorithm to do this ? How does the online ones do it that have 50+ currencies to chose from ?
As you are finding out, putting names of the currencies in the conversion logic is not a good idea. The same applies with the conversion values. You should want to write code to minimize things like that. You want the actual conversion logic coded without explicitly knowing ("hard coding") the names of the currencies or their exchange rates.
Rather than have something like actualType.equals("POUND") in your code, you want to try to have code that has each value represented by a variable: actualType.equals(otherType).
In real life, your data would come from an external source, such as a text file, a database, or another computer. In your small demo app, you might want to have the data load when the program starts, and be stored using array(s) and or (a) Collection object(s). At this time, you would also load the values in the Spinner objects, with the same data.
You might think about whether it is worth having another class or not:
class Money {
String name;
double conversionValue;
Money (String name, double value) {
this.name = name;
conversionValue = value;
}
And so on. (Note: I omitted visibility specifiers.)
In your conversion app, you could simulate the external source with an array:
Money [] market = { new Money ("Euro", 1.00), new Money ("USD", 1.00),
new Money ("Pound", 1.15), new Money ("Yen", 0.007),
new Money ("Rupee", 0.0125), ... };
An alternative to creating another class to glue a currency and exchange factor is to use a Map <String, Double>, with the name of the currency as the key and the exchange factor as the value.
So, the conversion app might have a method like this:
public double convertMoney (String selling, int amt, String buying)
{ ...
Depending on how the names and values were stored, it would use the string values to look up 2 conversion values. The exchange rate would be conversion value associated with selling divided by the conversion value associated with buying.

Issue converting double to boolean

I am working on a project in my Java class that is using multiple classes as well as GUI (not sure if that info is relevant). My group partner and I have come across an issue though. We have a Validator class, that should validate a "SSN" but we are continuously given the error:
java:146: error: incompatible types: double cannot be converted to boolean
if(Validator.isValidSSN(jTextFieldEmpSSN)){
Now obviously java:146 is the line. the code we have for each class is:
employeeUI class (the one showing the error):
private void jButtonEnterActionPerformed(java.awt.event.ActionEvent evt)
{
Employee e=new Employee();
if(Validator.isValidName(jTextFieldEmpFirst)){
if(Validator.isValidName(jTextFieldEmpLast)){
if(Validator.isValidEmail(jTextFieldEmpEmail)){
if(Validator.isValidSSN(jTextFieldEmpSSN)){
e.setFirstName(jTextFieldEmpFirst.getText());
e.setLastName(jTextFieldEmpLast.getText());
e.setEmailAdd(jTextFieldEmpEmail.getText());
e.setSSN(Integer.parseInt(jTextFieldEmpSSN.getText()));
}}}}
and the Validator class for isValidSSN is:
public static double isValidSSN(JTextField textfield)
{
double number = 0;
boolean inRange = false;
while(!inRange)
{
number = Double.parseDouble(textfield.getText());
if (number >= 100000000 && number <= 999999999)
{
inRange = true;
} else {}
}
return number;
}
We have been beating our head on how to fix this for quite some time, but are coming up at a loss. Are we missing something? we would greatly appreciate any help with this.
If I ask, "Is 123-45-6789" a valid SSN?" you wouldn't reply "123456789.0", would you? You'd give me a yes or a no. By returning double your method is doing the former. It's responding with a number instead of an answer to the question.
A good rule of thumb is that methods starting with is or has should return booleans. "Is this a valid SSN?" is a yes/no question, so isValidSSN should return the programming equivalent of yes/no.
public static boolean isValidSSN(JTextField textfield)
There are a couple of other design points here:
The loop isn't necessary. The SSN is either valid or it isn't.
A text field is not itself an SSN. It holds some text, and that text is the SSN. Rather than taking a text field and looking up the text in the field with getText(), it'd be better to have isValidSSN take the text directly. Let the caller extract the text from the text field.
In broader terms this is known as the single responsibility principle. Every method should ideally do just one thing.
Result:
public static boolean isValidSSN(String ssn) {
double number = Double.parseDouble(ssn);
if (number >= 100000000 && number <= 999999999) {
return true;
}
else {
return false;
}
}
P.S. If I don't mention it someone will surely comment that the if and else blocks aren't necessary; one can return the if result directly. They would be right, though I consider it a bit of an advanced trick. It would look like so:
public static boolean isValidSSN(String ssn) {
double number = Double.parseDouble(ssn);
return number >= 100000000 && number <= 999999999;
}

Elastic Search - Boosting/Scoring - Two words with different length

When querying a field with the query 'text', and finding two document with 'text abcd' and 'text ab', they both get the same score.
Is there a way to increase the score for 'text ab', since it is shorter?
This seems to be predicated on a misconcepttion of what length refers to in terms of lucene scoring. It's useful to think of tokens as the atomic unit of indexed text, rather than characters. The length lucene considers in scoring is the number of tokens in the fields. Both of the fields you've indicated have exactly two tokens. They have the same length, and thus their length norms are also equal, and they don't impact relative scoring.
If you had a fields with three terms, you would actually see a score impact from the length:
Field: "text ab" -- lengthnorm = 1/√2 = 0.7
Field: "text abcd" -- lengthnorm = 1/√2 = 0.7
Field: "text abc def ghi" -- lengthnorm = 1/√4 = 0.5
That norm is multiplied into the score, so the last document listed there will have a bit lower score.
If you're not sold on the idea of thinking of content in units of terms rather than characters:
Since the length you are considering works on characters, implementing this definitely goes against the grain somewhat. You are on the right track thinking about norms, though. This should definitely be preprocessed at index time and stored as a norm.
You will need to implement this in a custom similarity class. I'll assume we like the rest of DefaultSimilarity, so you can extend it, and override LengthNorm to make this simple. You can pretty easily leverage the field offset to get:
public class MySimilarity extends DefaultSimilarity {
#Override
public float lengthNorm(FieldInvertState state) {
return state.getBoost() * ((float) (1.0 / Math.sqrt(state.getOffset())));
}
}
And there you have it. A test run for the documents and query given show:
Field: "text ab" -- total score = 0.18579213
Field: "text abcd" -- total score = 0.18579213
Field: "text abcdefghi" -- total score = 0.1486337
So, you can see from the longer document I added the it is working, so then why do "text ab" and "text abcd" still have the same score?
Norms are stored in a hyper-compressed form, in a single byte. They only have a 3-bit mantissa, which gives them slightly less than 1 decimal digit of precision. As such, the difference with only those two added characters is just not enough to matter given the compression scheme. When it comes to this sort of boosting, common wisdom is: "Only big differences matter" (see the DefaultSimilarity documentation)
So, "Who cares about saving some memory at search time? Small differences matter to me!", I hear you say.
All right, you'll need to override encodeNorm and decodeNorm. Since these are final in DefaultSimilarity, you'll instead need to extend TFIDFSimilarity. I'd just start by copying the source for of DefaultSimilarity. In the end you could use something like this:
public class MySimilarity extends TFIDFSimilarity {
public MySimilarity() {}
#Override
public float coord(int overlap, int maxOverlap) {
return overlap / (float)maxOverlap;
}
#Override
public float queryNorm(float sumOfSquaredWeights) {
return (float)(1.0 / Math.sqrt(sumOfSquaredWeights));
}
//Since length norms are generally going to leave us with results less than one, multiply
//by a sufficiently large number to not lose all our precision when casting to long
private static final float NORM_ADJUSTMENT = Integer.MAX_VALUE;
#Override
public final long encodeNormValue(float f) {
return (long) (f * NORM_ADJUSTMENT);
}
#Override
public final float decodeNormValue(long norm) {
System.out.println(norm);
return ((float) norm) / NORM_ADJUSTMENT;
}
#Override
public float lengthNorm(FieldInvertState state) {
return state.getBoost() * ((float) (1.0 / Math.sqrt(state.getOffset())));
}
#Override
public float tf(float freq) {
return (float)Math.sqrt(freq);
}
#Override
public float sloppyFreq(int distance) {
return 1.0f / (distance + 1);
}
#Override
public float scorePayload(int doc, int start, int end, BytesRef payload) {
return 1;
}
#Override
public float idf(long docFreq, long numDocs) {
return (float)(Math.log(numDocs/(double)(docFreq+1)) + 1.0);
}
#Override
public String toString() {
return "DefaultSimilarity";
}
}
And now I get:
Field: "text ab" -- total score = 0.2518424
Field: "text abcd" -- total score = 0.22525471
Field: "text abcdefghi" -- total score = 0.1839197

Calculating math in GPS format

I'm making a Android Application to calculate Math in GPS Format.
Example:
Given
N 48°44.(30x4) E 019°08.[(13x31)+16]
the App calculates it, and result is:
N 48°44.120 E 019°08.419
Is it possible to do this?
I searched for plugins and solutions, but it's all just for math strings like as "14 + 6".
I am assuming you are working in Java as it is tagged in your question.
You could create a new public class for your GPS coordinates, and store the actual value of the coordinate in the lowest division, which according to your example appears to be minutes or seconds. This allows you to store the value as an int or a double with whatever precision you wish. You could then create a set of private and public methods to complete your mathematical operations and others to display your values in the appropriate fashion:
public class GPSCoordinate {
private double verticalcoord;
private double horizontalcoord;
//Constructors
GPSCoordinate(){
setVertical(0);
setHorizontal(0);
}
GPSCoordinate(double vert, double horiz){
setVertical(vert);
setHorizontal(horiz);
}
//Display methods
public String verticalString(){
return ((int)verticalcoord / 60) + "°" + (verticalcoord - ((int)verticalcoord / 60) *60);
}
public String horizontalString(){
return ((int)horizontalcoord / 60) + "°" + (horizontalcoord - ((int)horizontalcoord / 60) *60);
}
//Setting Methods
public void setVertical(double x){
this.verticalcoord = x;
}
public void setHorizontal(double x){
this.horizontalcoord = x;
}
//Math Methods
public void addMinutesVertical(double x){
this.verticalcoord += x;
}
}
This will allow you to initiate an instance in your main code with a given GPS coordinate, and then you can call your math functions on it.
GPSCoordinate coord1 = new GPSCoordinate(567.23, 245);
coord1.addMinutesVertical(50);
coord1.otherMathFunction(50 * 30);
You will, of course, need to refine the above to make it fit your project. If this isn't helpful, please provide more specifics and I'll see if I can think of anything else that might fit what your looking for.
Can't you just substring the whole thing and search for the expression in the brackets? Then it's just a matter of simple calculation. If I understood the question correctly. The gps data doesn't look like an ordinary expression, so you can't appy math() directly.

Abstract Concept Assignment [closed]

This question is unlikely to help any future visitors; it is only relevant to a small geographic area, a specific moment in time, or an extraordinarily narrow situation that is not generally applicable to the worldwide audience of the internet. For help making this question more broadly applicable, visit the help center.
Closed 10 years ago.
So my questions are geared directly to my homework. Before you ask, yes I've looked at other questions and I have looked at the java docs to try and help me but I only understand so much..
You have become a restaurant mogul. You own several fast food chains. However, you now need to set a standard that all of your fast food chain must follow in order to have your software be uniform across the board. There will be some rules that will be the same for all restaurants.
Create an Abstract Class named Restaurant
Create a function/method that will print the name of the restaurant when called.
Create an abstract function/method named total price
Create an abstract function/method named menu items
Create an abstract function/method name location
Create a Class called McDonalds that extends Restaurant
Implement all abstract methods
Add logic so that the total price method/function will give the total price of the meal including a 6% tax
Add a method that returns a Boolean named hasPlayPlace. Which returns true when this location has a playplace
Create a Constructor that will set the name of the Mcdonalds, location, and hasPlayPlace
public class McDonalds extends Restaurant {
private String name;
private String location;
private boolean hasPlayPlace;
Scanner input = new Scanner(System.in);
public McDonalds (String name, String location, boolean hasPlayPlace) {
setName(name);
setLocation(location);
setHasPlayPlace(hasPlayPlace);
}
McDonalds location1 = new McDonalds("McDonalds", "Kirkman", false);
McDonalds location2 = new McDonalds("McDonalds 2", "International Dr.", true);
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getLocation() {
return location;
}
public void setLocation(String location){
this.location = location;
}
public boolean isHasPlayPlace() {
return hasPlayPlace;
}
public void setHasPlayPlace(boolean hasPlayPlace) {
this.hasPlayPlace = hasPlayPlace;
}
public void totalPrice() {
double totalPrice = 0;
double tax = 0.06;
totalPrice += (totalPrice * tax);
}
public void menuItems() {
//some syntax is wrong in this method
double mcChicken = 1;
double fries = 1.25;
System.out.println("1. Mc Chicken $1");
System.out.println("2. Fries $1.25");
int choice = input.nextInt();
switch (choice){
case 1: mcChicken *= tax;
case 2: fries *= tax;
}
}
public void location() {
//Don't know what's supposed to go in here.
//But I've implemented the method as I was supposed to.
}
}
Does it all make sense is basically what i'm asking.
What should go in the location method?
What's the use of getters and setters within this class and did I do it right?
1) Your constructor is structured fine, but you should use Strings instead of chars for the name and location. A char will only hold one character.
2) You can create multiple instances of a class:
McDonalds location1 = new McDonalds("McDonald", "Kirkman", true);
McDonalds location2 = new McDonalds("McDonald2", "Kirkman", false);
3) You should add the tax to the price as a percentage, not a sum: price * 1.06. Be careful not to change the price w/o tax when you print the total price.
Name and location should be String not char.
I like the style of calling setters from within the constructor, because its a form of code reuse, especially if there are special checks being made on those values, such as not being null - calling he setter means you only check this in one place.
Your code won't compile, but you're close:
McDonalds location1 = new McDonalds("Some name", "Kirkman", true);
Your calculation is a little off too:
double tax = 0.06;
totalPrice *= (tax + 1);
However, this is dangerous because if called twice, it will add the tax twice. It would be better to have a method return the tax included price which calculates it every time. Having a getter with side effects is a design error. Ie have thus:
public double getTaxIncPrice() {
double tax = 0.06;
return totalPrice * (1 + tax);
}
In addition to the problem that Bohemian pointed out (name and location should be String, not char):
Your constructor call will need quotes on the String parameters:
McDonalds location1 = new McDonalds("McDonald", "Kirkman", true);
and your tax calculation is incorrect - you will need to multiply the total amount by the tax percentage, and you will have to wait until you actually have a total to do the calculation.
Just editted my code and provided the question. Your guys inputs helped so far.
public String TacoBellSauce(String fire, String hot, String mild) {
System.out.println("What sauce would you like to have?");
System.out.println("1. Fire");
System.out.println("2. Hot");
System.out.println("3. Mild");
int choice = input.nextInt();
switch(choice) {
case 1:
return fire;
case 2:
return hot;
case 3:
return mild;
}
return null;
}
Here is also my method for the TacoBell class. How would I return it in the Test class? It says to make a method within TacoBell that returns a string of what hot sauce I would like. But then it says within the test class to call hotsauce and return hot. I haven't created that class yet cause I'm focused on correcting everything with McDonalds and TacoBell.

Categories

Resources