How to create a variable that contains an Operator in Java? - java

I'm trying to write a program in 30 lines or less for my class (self imposed challenge).
The program asks the user a simple addition, division, multiplication, or subtraction question and the player answers, rinse and repeat 10 times, then the player is asked if they want to continue or end the program. The type of question (add, mult, etc.) should be selected randomly.
So that I don't need to use a huge switch case or if-else tree, I want to know if there is any way to contain an operator in a variable, and then use it later.
Example:
var operator = +;
int[] n = {1, 2};
System.out.println(n[0] operator n[1]);
And the output would be "3"
That's an example of what kinda thing I want to do. Is this possible?

No, you can't do that directly. You will have to make a type that represents an operator.
The most common way to do this is with an enum:
enum Operator {
PLUS {
#Override int operate(int a, int b) {
return a + b;
}
};
abstract int operate(int a, int b);
}
Operator operator = Operator.PLUS;
int[] n = {1, 2};
System.out.println(operator.operate(n[0], n[1]));

It's not possible to assign an operator to a variable.
in 30 lines or less ... the program asks the user a simple addition, division, multiplication, or subtraction
If you want to implement it using as fewer lines as possible, build-in functional interfaces will be a good choice. For that, you need IntBinaryOperator that represents an operation done on two int arguments.
Functional interface can be implemented either by using a lambda expression or a method reference (also, you can do that with an anonymous inner class as well by it'll not be shorter). Addition operation can be represented like that:
IntBinaryOperator add = Integer::sum; // or (i1, i2) -> i1 + i2
The type of question (add, mult, etc.) should be selected randomly
For that, firstly, you need to define a Random object. In order to obtain a random integer in the given range, use nextInt() method that expects an int bound, and returns a value from 0 up to the bound (exclusive):
rand.nextInt(RANGE)
To avoid hard-coding, RANGE should be defined as a global constant.
Because your application has to interact with the user, every operation should be associated with a name that will be exposed to the user.
It can be done by declaring a record (a special kind class with final field and auto-generated constructor, getters, hashCode/equals, toString()). Syntax for declaring records is very concise:
public record Operation(String name, IntBinaryOperator operation) {}
Records representing arithmetical operations can be stored in a list. And you can pick an operation by generating a random index (from 0 up to list size).
operations.get(rand.nextInt(operations.size()))
Unlike the common getters, names of getters that will be generated by the compiler for the record will identical to names of its fields, i.e. name() and operation().
In order to use the function retrieved from the record, you need to invoke the method applyAsInt() on it, passing the two previously generated numbers.
That's how it might look like.
public class Operations {
public static final int RANGE = 100;
public static final Random rand = new Random();
public record Operation(String name, IntBinaryOperator operation) {}
public static final List<Operation> operations =
List.of(new Operation("add", Integer::sum), new Operation("sub", (i1, i2) -> i1 - i2),
new Operation("mult", (i1, i2) -> i1 * i2), new Operation("div", (i1, i2) -> i1 / i2));
public static void main(String[] args) {
// you code (instansiate a scanner, enclose the code below with a while loop)
for (int i = 0; i < 10; i++) {
Operation oper = operations.get(rand.nextInt(operations.size()));
int operand1 = rand.nextInt(RANGE);
int operand2 = rand.nextInt(RANGE);
System.out.println(operand1 + " " + oper.name() + " " + operand2); // exposing generated data to the user
int userInput = sc.nextInt(); // reading user's input
int result = oper.operation().applyAsInt(operand1,operand2); // exposing the result
System.out.println(result + "\n__________________");
}
// termination condition of the while loop
}
}
That's an example of the output the user will see:
38 add 67
105 // user input
105
_____________________
97 sub 15
...

Unfortunately java supports neither operator overloading nor infix notation, making it impossible to do so in source code.

Related

java 2d memory address

in java if we have:
int[][] x = new int[3][3];
the memory address of x is different from the memory address of x[0]. As x[0] gives the memory address of the first column. So the memory address of x[0][0] is different than the memory address of x[0].
are there any computer languages that store a 2d array as a matrix and not as an array of arrays?
would the address of x always be different from x[0] and the address of x[0] equal x[0][0]?
are there any computer languages that store a 2d array as a matrix and
not as an array of arrays?
Yes. Or, at least, there used to be.
There is the possibility of using an assembler language, where the programmer has extreme control over how arrays might be handled. But, let's assume the question is about high-level languages (>=3GL).
I don't know about modern version of Fortran, but the early versions of FORTRAN stored any array, including multi-dimensional arrays, in consecutive storage locations. So, for example, if you declared an array as INTEGER FOO (3,4,5), then FOO and FOO (1,1,1) would have the same memory address. FOO would occupy a block of 60 INTEGER sized locations. The compiler generates code to find, from the subscript values, the location of an element in a manner similar to what #Jesse described in a comment on the question. It's slightly different to allow for the fact that FORTRAN subscripts started at one instead of zero.
By the way, FORTRAN subscript are in opposite order of most other languages. In Java, C, C++, and COBOL, the major subscripts are to the left. In FORTRAN, they were to the right.
FORTRAN syntax didn't allow missing subscripts. So, continuing the example, something like FOO (2,3) would generate a compiler error.
Now, suppose there was the following method:
REAL FUNCTION MEAN (ARR, N)
INTEGER N, ARR (N)
REAL SUM
DO 400 I = 1,N,1
SUM = SUM + ARR (I)
400 CONTINUE
RETURN SUM / N
END
A programmer could it use to calculate the mean of the entire FOO array, or any part of it:
REAL ALLMEAN, LEVEL3MEAN, ROWMEAN
ALLMEAN = MEAN (FOO(1,1,1), 60)
LEVEL3MEAN = MEAN (FOO(1,1,3), 12)
ROWMEAN = MEAN (FOO(1,2,3), 4)
Suppose, for some strange reason, there was this:
AVGPART = MEAN (FOO (2,3,2), 20)
This would use 20 consecutive elements of FOO, even if those elements were in different rows or levels.
When I took a C++ course, someone didn't like having to type separate [x] subscripts for multidimensional arrays. Instead of foo [2][1][0], he would rather type something like foo.get (2,1,0), so wrote a convenience wrapper class for an array. Such code might still have foo [t][r][c] inside the wrapper class. Or, it could allocate a 1D array. Once the class was created, it allowed him to specify subscripts as arguments in a call to a method.
Code in Java to do that, using the 1D array option, might look like this:
public class Block {
// class for regular 3D Array
private int [] array;
private int rows, int columns, int levels;
public Block (int t, int r, int c) {
rows = r;
columns = c;
levels = t;
array = new array [ t * r * c];
}
public int get (int t, int r, int c) {
return array [ t * rows * columns + r * columns + c ];
}
public void set (int value, int t, int r, int c) {
array [ t * rows * columns + r * columns + c ] = value;
}
...
}

Compiler error: possible lossy conversion from long to int___Fibonacci

This is my first post here so if I made some mistakes I am sorry. Also, coding is not necessarily my thing, I am trying to get the hang of it and doing my best.
So basically, I have to solve this problem using dynamic programming:
Triponacci is a series where the nth value is equal to the sum of the previous 3 values. The initial 3 values (base values) of our series are {0, 1, 2}.Note that the very first value in our series is 0th value.
Output will be in the form of a statement: Triponacci(2) = 2 The value in the parenthesis is the input value n. The number to the right of the equals sign is the value of the nth element of the series.
Triponacci(0) = 0 Triponacci(3) = 3
I thought, ok easy peasy Fibonacci with an extra step, right? Well... this is what I did:
static long[] storage;
public static long trip(int n)
{
if(n<=2)
return n;
if(storage[n]<0)
return storage[n];
long result= trip(n-1) + trip(n-2)+trip(n-3);
storage[n]= result;
return result;
}
public static void main(String[]args)
{
Scanner scan= new Scanner(System.in);
long n = scan.nextLong();
storage= new long[n+1];
long res= trip(n);
System.out.println(res);
}
At first it looked fine to me but when I compiled it threw multiple errors at me.
Triponacci.java:22: error: incompatible types: possible lossy conversion from long to int
storage= new long\[n+1\];
^
Triponacci.java:23: error: incompatible types: possible lossy conversion from long to int
long res= trip(n);
^
What should I do to make it work? Thank you in advance for your time and answers.
I thought I should use long instead of int due to boundaries issues.
expected to work fine but well.
You're asking for a long which is a primitive type that can hold larger numbers than ints. If your intent is to actually allow the user to enter 'Triponacci(4000000000123451)' - then you have a much bigger problem, that's way too large and requires BigInteger and probably a better algorithm than this. Using long can make sense, but only for the outputs (the sums - the value of the storage array). NOT for the inputs.
Note that in java arrays must have int indices, so in that sense, you need a much more complicated algorithm in any case if you really intend for the user to be able to enter a number beyond the confines of int (which are: plus 2 billion to minus 2 billion, approximately).
NB: Your code has a bug; if storage[n] is less than 0? I think you meant more than 0.
static long[] storage;
public static long trip(int n) {
if (n <= 2) return n;
if (storage[n] != 0) return storage[n];
return storage[n] = trip(n-1) + trip(n-2) + trip(n-3);
}
public static void main(String[]args) {
Scanner scan = new Scanner(System.in);
int n = scan.nextInt();
storage = new long[n+1];
long res = trip(n);
System.out.println(res);
}

Choose best combinations of operators to find target number

I have an array of operations and a target number.
The operations could be
+ 3
- 3
* 4
/ 2
I want to find out how close I can get to the target number by using those operations.
I start from 0 and I need to iterate through the operations in that order, and I can choose to either use the operation or not use it.
So if the target number is 13, I can use + 3 and * 4 to get 12 which is the closest I can get to the target number 13.
I guess I need to compute all possible combinations (I guess the number of calculations is thus 2^n where n is the number of operations).
I have tried to do this in java with
import java.util.*;
public class Instruction {
public static void main(String[] args) {
// create scanner
Scanner sc = new Scanner(System.in);
// number of instructions
int N = sc.nextInt();
// target number
int K = sc.nextInt();
//
String[] instructions = new String[N];
// N instructions follow
for (int i=0; i<N; i++) {
//
instructions[i] = sc.nextLine();
}
//
System.out.println(search(instructions, 0, N, 0, K, 0, K));
}
public static int search(String[] instructions, int index, int length, int progressSoFar, int targetNumber, int bestTarget, int bestDistance) {
//
for (int i=index; i<length; i++) {
// get operator
char operator = instructions[i].charAt(0);
// get number
int number = Integer.parseInt(instructions[i].split("\\s+")[1]);
//
if (operator == '+') {
progressSoFar += number;
} else if (operator == '*') {
progressSoFar *= number;
} else if (operator == '-') {
progressSoFar -= number;
} else if (operator == '/') {
progressSoFar /= number;
}
//
int distance = Math.abs(targetNumber - progressSoFar);
// if the absolute distance between progress so far
// and the target number is less than what we have
// previously accomplished, we update best distance
if (distance < bestDistance) {
bestTarget = progressSoFar;
bestDistance = distance;
}
//
if (true) {
return bestTarget;
} else {
return search(instructions, index + 1, length, progressSoFar, targetNumber, bestTarget, bestDistance);
}
}
}
}
It doesn't work yet, but I guess I'm a little closer to solving my problem. I just don't know how to end my recursion.
But maybe I don't use recursion, but should instead just list all combinations. I just don't know how to do this.
If I, for instance, have 3 operations and I want to compute all combinations, I get the 2^3 combinations
111
110
101
011
000
001
010
100
where 1 indicates that the operation is used and 0 indicates that it is not used.
It should be rather simple to do this and then choose which combination gave the best result (the number closest to the target number), but I don't know how to do this in java.
In pseudocode, you could try brute-force back-tracking, as in:
// ops: list of ops that have not yet been tried out
// target: goal result
// currentOps: list of ops used so far
// best: reference to the best result achieved so far (can be altered; use
// an int[1], for example)
// opsForBest: list of ops used to achieve best result so far
test(ops, target, currentOps, best, opsForBest)
if ops is now empty,
current = evaluate(currentOps)
if current is closer to target than best,
best = current
opsForBest = a copy of currentOps
otherwise,
// try including next op
with the next operator in ops,
test(opsAfterNext, target,
currentOps concatenated with next, best, opsForBest)
// try *not* including next op
test(opsAfterNext, target, currentOps, best, opsForBest)
This is guaranteed to find the best answer. However, it will repeat many operations once and again. You can save some time by avoiding repeat calculations, which can be achieved using a cache of "how does this subexpression evaluate". When you include the cache, you enter the realm of "dynamic programming" (= reusing earlier results in later computation).
Edit: adding a more OO-ish variant
Variant returning the best result, and avoiding the use of that best[] array-of-one. Requires the use of an auxiliary class Answer with fields ops and result.
// ops: list of ops that have not yet been tried out
// target: goal result
// currentOps: list of ops used so far
Answer test(ops, target, currentOps, opsForBest)
if ops is now empty,
return new Answer(currentOps, evaluate(currentOps))
otherwise,
// try including next op
with the next operator in ops,
Answer withOp = test(opsAfterNext, target,
currentOps concatenated with next, best, opsForBest)
// try *not* including next op
Answer withoutOp = test(opsAfterNext, target,
currentOps, best, opsForBest)
if withOp.result closer to target than withoutOp.target,
return withOp
else
return withoutOp
Dynamic programming
If the target value is t, and there are n operations in the list, and the largest absolute value you can create by combining some subsequence of them is k, and the absolute value of the product of all values that appear as an operand of a division operation is d, then there's a simple O(dkn)-time and -space dynamic programming algorithm that determines whether it's possible to compute the value i using some subset of the first j operations and stores this answer (a single bit) in dp[i][j]:
dp[i][j] = dp[i][j-1] || dp[invOp(i, j)][j-1]
where invOp(i, j) computes the inverse of the jth operation on the value i. Note that if the jth operation is a multiplication by, say, x, and i is not divisible by x, then the operation is considered to have no inverse, and the term dp[invOp(i, j)][j-1] is deemed to evaluate to false. All other operations have unique inverses.
To avoid loss-of-precision problems with floating point code, first multiply the original target value t, as well as all operands to addition and subtraction operations, by d. This ensures that any division operation / x we encounter will only ever be applied to a value that is known to be divisible by x. We will essentially be working throughout with integer multiples of 1/d.
Because some operations (namely subtractions and divisions) require solving subproblems for higher target values, we cannot in general calculate dp[i][j] in a bottom-up way. Instead we can use memoisation of the top-down recursion, starting at the (scaled) target value t*d and working outwards in steps of 1 in each direction.
C++ implementation
I've implemented this in C++ at https://ideone.com/hU1Rpq. The "interesting" part is canReach(i, j); the functions preceding this are just plumbing to handle the memoisation table. Specify the inputs on stdin with the target value first, then a space-separated list of operations in which operators immediately preceed their operand values, e.g.
10 +8 +11 /2
or
10 +4000 +5500 /1000
The second example, which should give the same answer (9.5) as the first, seems to be around the ideone (and my) memory limits, although this could be extended somewhat by using long long int instead of int and a 2-bit table for _m[][][] instead of wasting a full byte on each entry.
Exponential worst-case time and space complexity
Note that in general, dk or even just k by itself could be exponential in the size of the input: e.g. if there is an addition, followed by n-1 multiplication operations, each of which involves a number larger than 1. It's not too difficult to compute k exactly via a different DP that simply looks for the largest and smallest numbers reachable using the first i operations for all 1 <= i <= n, but all we really need is an upper bound, and it's easy enough to get a (somewhat loose) one: simply discard the signs of all multiplication operands, convert all - operations to + operations, and then perform all multiplication and addition operations (i.e., ignoring divisions).
There are other optimisations that could be applied, for example dividing through by any common factor.
Here's a Java 8 example, using memoization. I wonder if annealing can be applied...
public class Tester {
public static interface Operation {
public int doOperation(int cur);
}
static Operation ops[] = { // lambdas for the opertions
(x -> x + 3),
(x -> x - 3),
(x -> x * 4),
(x -> x / 2),
};
private static int getTarget(){
return 2;
}
public static void main (String args[]){
int map[];
int val = 0;
int MAX_BITMASK = (1 << ops.length) - 1;//means ops.length < 31 [int overflow]
map = new int[MAX_BITMASK];
map[0] = val;
final int target = getTarget();// To get rid of dead code warning
int closest = val, delta = target < 0? -target: target;
int bestSeq = 0;
if (0 == target) {
System.out.println("Winning sequence: Do nothing");
}
int lastBitMask = 0, opIndex = 0;
int i = 0;
for (i = 1; i < MAX_BITMASK; i++){// brute force algo
val = map[i & lastBitMask]; // get prev memoized value
val = ops[opIndex].doOperation(val); // compute
map[i] = val; //add new memo
//the rest just logic to find the closest
// except the last part
int d = val - target;
d = d < 0? -d: d;
if (d < delta) {
bestSeq = i;
closest = val;
delta = d;
}
if (val == target){ // no point to continue
break;
}
//advance memo mask 0b001 to 0b011 to 0b111, etc.
// as well as the computing operation.
if ((i & (i + 1)) == 0){ // check for 2^n -1
lastBitMask = (lastBitMask << 1) + 1;
opIndex++;
}
}
System.out.println("Winning sequence: " + bestSeq);
System.out.println("Closest to \'" + target + "\' is: " + closest);
}
}
Worth noting, the "winning sequence" is the bit representation (displayed as decimal) of what was used and what wasn't, as the OP has done in the question.
For Those of you coming from Java 7, this is what I was referencing for lambdas: Lambda Expressionsin GUI Applications. So if you're constrained to 7, you can still make this work quite easily.

Java implementation-How to improve the speed of hash table

I am implementing a hash table (as per requirements). It works ok with a small input but unfortunately it's way too slow when dealing with a large number of input. I tried BufferedInputStream but it doesn't make any differences. Basically I implemented it following the logic below. Any ideas how I can improve the speed? Is there a specific function that causes the bad performance? Or we might need to close the Scanner?
int [] table = new int [30000];// creat an array as the table
Scanner scan = new Scanner (System.in); //use scanner to read the input file.
while (scan.hasNextLine()) {
//read one line at a time, and a sequence of int into an array list called keys
// functions used here is string.split(" ");
}
hashFuction{
//use middle-squaring on each elements to the array list keys.
// Math.pow() and % 30000, which is the table size, to generate the hash value
// assign table [hashvalue]= value
}
So first, you should now what part of the program is slow. Optimizing everything is a stupid idea, optimizing the fast part is even worse.
Math.pow() and % 30000, which is the table size
This is pretty wrong.
Never use floating point operations for things like hashing. It's slow and badly distributed.
Never use a table size which is neither a power of two nor prime.
You failed to tell us anything about what you're hashing and why... so let's assume you need to map a pair of two ints into the table.
class IntPair {
private int x;
private int y;
public int hashCode() {
// the multiplier must be odd for good results
// its exact value doesn't matter much, but it mustn't equal to your table size; ideally, it should be co-prime
return 54321 * x + y;
}
public boolean equals() {
do yourself
}
}
//// Prime table size. The division is slow, but it works slightly better than power of two.
int[] table = new int[30011]; // this is a prime
int hashCodeToIndex(int hashCode) {
int nonNegative = hashCode & Integer.MAX_VALUE;
return nonNegative % table.length;
}
//// Power of two table size. No division, faster.
int[] table2 = new int[1<<15]; // this is 2**15, i.e., 32768
int smear(int hashCode) {
// doing nothing may be good enough, if the hashCode is well distributed
// otherwise, see e.g., https://github.com/google/guava/blob/c234ed7f015dc90d0380558e663f57c5c445a288/guava/src/com/google/common/collect/Hashing.java#L46
return hashCode;
}
int hashCodeToIndex(int hashCode) {
// the "&" cleans all unwanted bits
return smear(hashCode) & (table2.length - 1);
}
// an alternative, explanation upon request
int hashCodeToIndex2(int hashCode) {
return smear(hashCode) >>> 17;
}

How to add two java.lang.Numbers?

I have two Numbers. Eg:
Number a = 2;
Number b = 3;
//Following is an error:
Number c = a + b;
Why arithmetic operations are not supported on Numbers? Anyway how would I add these two numbers in java? (Of course I'm getting them from somewhere and I don't know if they are Integer or float etc).
You say you don't know if your numbers are integer or float... when you use the Number class, the compiler also doesn't know if your numbers are integers, floats or some other thing. As a result, the basic math operators like + and - don't work; the computer wouldn't know how to handle the values.
START EDIT
Based on the discussion, I thought an example might help. Computers store floating point numbers as two parts, a coefficient and an exponent. So, in a theoretical system, 001110 might be broken up as 0011 10, or 32 = 9. But positive integers store numbers as binary, so 001110 could also mean 2 + 4 + 8 = 14. When you use the class Number, you're telling the computer you don't know if the number is a float or an int or what, so it knows it has 001110 but it doesn't know if that means 9 or 14 or some other value.
END EDIT
What you can do is make a little assumption and convert to one of the types to do the math. So you could have
Number c = a.intValue() + b.intValue();
which you might as well turn into
Integer c = a.intValue() + b.intValue();
if you're willing to suffer some rounding error, or
Float c = a.floatValue() + b.floatValue();
if you suspect that you're not dealing with integers and are okay with possible minor precision issues. Or, if you'd rather take a small performance blow instead of that error,
BigDecimal c = new BigDecimal(a.floatValue()).add(new BigDecimal(b.floatValue()));
It would also work to make a method to handle the adding for you. Now I do not know the performance impact this will cause but I assume it will be less than using BigDecimal.
public static Number addNumbers(Number a, Number b) {
if(a instanceof Double || b instanceof Double) {
return a.doubleValue() + b.doubleValue();
} else if(a instanceof Float || b instanceof Float) {
return a.floatValue() + b.floatValue();
} else if(a instanceof Long || b instanceof Long) {
return a.longValue() + b.longValue();
} else {
return a.intValue() + b.intValue();
}
}
The only way to correctly add any two types of java.lang.Number is:
Number a = 2f; // Foat
Number b = 3d; // Double
Number c = new BigDecimal( a.toString() ).add( new BigDecimal( b.toString() ) );
This works even for two arguments with a different number-type. It will (should?) not produce any sideeffects like overflows or loosing precision, as far as the toString() of the number-type does not reduce precision.
java.lang.Number is just the superclass of all wrapper classes of primitive types (see java doc). Use the appropriate primitive type (double, int, etc.) for your purpose, or the respective wrapper class (Double, Integer, etc.).
Consider this:
Number a = 1.5; // Actually Java creates a double and boxes it into a Double object
Number b = 1; // Same here for int -> Integer boxed
// What should the result be? If Number would do implicit casts,
// it would behave different from what Java usually does.
Number c = a + b;
// Now that works, and you know at first glance what that code does.
// Nice explicit casts like you usually use in Java.
// The result is of course again a double that is boxed into a Double object
Number d = a.doubleValue() + (double)b.intValue();
Use the following:
Number c = a.intValue() + b.intValue(); // Number is an object and not a primitive data type.
Or:
int a = 2;
int b = 3;
int c = 2 + 3;
I think there are 2 sides to your question.
Why is operator+ not supported on Number?
Because the Java language spec. does not specify this, and there is no operator overloading. There is also not a compile-time natural way to cast the Number to some fundamental type, and there is no natural add to define for some type of operations.
Why are basic arithmic operations not supported on Number?
(Copied from my comment:)
Not all subclasses can implement this in a way you would expect. Especially with the Atomic types it's hard to define a usefull contract for e.g. add.
Also, a method add would be trouble if you try to add a Long to a Short.
If you know the Type of one number but not the other it is possible to do something like
public Double add(Double value, Number increment) {
return value + Double.parseDouble(increment.toString());
}
But it can be messy, so be aware of potential loss of accuracy and NumberFormatExceptions
Number is an abstract class which you cannot make an instance of. Provided you have a correct instance of it, you can get number.longValue() or number.intValue() and add them.
First of all, you should be aware that Number is an abstract class. What happens here is that when you create your 2 and 3, they are interpreted as primitives and a subtype is created (I think an Integer) in that case. Because an Integer is a subtype of Number, you can assign the newly created Integer into a Number reference.
However, a number is just an abstraction. It could be integer, it could be floating point, etc., so the semantics of math operations would be ambiguous.
Number does not provide the classic map operations for two reasons:
First, member methods in Java cannot be operators. It's not C++. At best, they could provide an add()
Second, figuring out what type of operation to do when you have two inputs (e.g., a division of a float by an int) is quite tricky.
So instead, it is your responsibility to make the conversion back to the specific primitive type you are interested in it and apply the mathematical operators.
The best answer would be to make util with double dispatch drilling down to most known types (take a look at Smalltalk addtition implementation)

Categories