With the help of some very nice people from this forum I've been able to translate some c++ into java language, but I'm not sure how to call this classes. Bassically what they are supposed to do is to return a "gen4 style" curve. If someone have an idea how to get this running please let me know!
/*
Derived from gen4 from the UCSD Carl package, described in F.R. Moore,
"Elements of Computer Music." It works like setline, but there's an
additional argument for each time,value pair (except the last). This
arg determines the curvature of the segment, and is called "alpha" in
the comments to trans() below. -JGG, 12/2/01
http://www.music.columbia.edu/cmc/rtcmix/docs/docs.html (maketable/gen4)
trans(a, alpha, b, n, output) makes a transition from <a> to <b> in
<n> steps, according to transition parameter <alpha>. It stores the
resulting <n> values starting at location <output>.
alpha = 0 yields a straight line,
alpha < 0 yields an exponential transition, and
alpha > 0 yields a logarithmic transition.
All of this in accord with the formula:
output[i] = a + (b - a) * (1 - exp(i * alpha / (n-1))) / (1 - exp(alpha))
for 0 <= i < n
*/
import java.lang.Math;
private static final int MAX_POINTS =1024;
public class gen{
int size; /* size of array to load up */
int nargs; /* number of arguments passed in p array */
float []pvals; /* address of array of p values */
double []array; /* address of array to be loaded up */
int slot; /* slot number, for fnscl test */
}
public static void fnscl(gen g) {
}
static void trans(double a, double alpha, double b, int n, double[] output) {
double delta = b - a;
if (output.length <= 1) {
output[0] = a;
return;
}
double interval = 1.0 / (output.length - 1);
if (alpha != 0) {
double denom = 1 / (1 - Math.exp(alpha));
for (int i = 0; i < output.length; i++)
output[i] = a + (1 - Math.exp(i * alpha * interval)) * delta * denom;
} else {
for (int i = 0; i < output.length; i++)
output[i] = a + i * delta * interval;
}
}
public static double gen4(gen g) {
int i;
int points = 0;
int seglen = 0;
double factor;
double time [] = new double[MAX_POINTS];
double value [] = new double[MAX_POINTS];
double alpha [] = new double[MAX_POINTS];
double ptr [];
if (g.nargs < 5 || (g.nargs % 3) != 2) /* check number of args */
System.out.println("gen4 usage: t1 v1 a1 ... tn vn");
if ((g.nargs / 3) + 1 > MAX_POINTS)
System.out.println("gen4 too many arguments");
for (i = points = 0; i < g.nargs; points++) {
time[points] = g.pvals[i++];
if (points > 0 && time[points] < time[points - 1])
System.out.println("gen4 non-increasing time values");
value[points] = g.pvals[i++];
if (i < g.nargs)
alpha[points] = g.pvals[i++];
}
factor = (g.size - 1) / time[points - 1];
for (i = 0; i < points; i++)
time[i] *= factor;
ptr = g.array;
for (i = 0; i < points - 1; i++) {
seglen = (int) (Math.floor(time[i + 1] + 0.5)
- Math.floor(time[i] + 0.5) + 1);
trans(value[i], alpha[i], value[i + 1], seglen, ptr);
ptr[i] += seglen - 1;
}
fnscl(g);
return 0.0;
}
If I understand your question correctly and you want to execute your program, you need some adjustments to your code.
You need to have a class. To execute it, you need a special main method.
/**
*Derived from...
*/
import java.lang.Math;
class Gen4Func {
class Gen {
// insert from question
}
public static void main(String[] args) {
// prepare parameters
// ...
// call your function
trans( ... );
// do more stuff
// ...
}
public static void fnscl(gen g) {
}
static void trans(double a, double alpha, double b, int n, double[] output) {
// insert from above
}
}
Save this to Gen4Func.java (must match class name). Then execute from via
> java Gen4Func
As I said: If I understand your question correctly.
HTH,
Mike
Bulky, copypaste to Gen.java and try setting Gen class fields with test values in main() method.
/*
* Derived from gen4 from the UCSD Carl package, described in F.R. Moore,
* "Elements of Computer Music." It works like setline, but there's an additional
* argument for each time,value pair (except the last). This arg determines the
* curvature of the segment, and is called "alpha" in the comments to trans()
* below. -JGG, 12/2/01
*
* http://www.music.columbia.edu/cmc/rtcmix/docs/docs.html (maketable/gen4)
*
*
*
* trans(a, alpha, b, n, output) makes a transition from <a> to <b> in <n>
* steps, according to transition parameter <alpha>. It stores the resulting <n>
* values starting at location <output>. alpha = 0 yields a straight line, alpha
* < 0 yields an exponential transition, and alpha > 0 yields a logarithmic
* transition. All of this in accord with the formula: output[i] = a + (b - a) *
* (1 - exp(i * alpha / (n-1))) / (1 - exp(alpha)) for 0 <= i < n
*/
public class Gen {
private static final int MAX_POINTS = 1024;
int size; //size of array to load up
int nargs; //number of arguments passed in p array
float[] pvals; //address of array of p values
double[] array; //address of array to be loaded up
int slot; //slot number, for fnscl test
public static void main(String[] args) {
Gen g = new Gen();
//initialize Gen fields here..
Gen.gen4(g);
}
public static void fnscl(Gen g) {
}
public static void trans(double a, double alpha, double b, int n, double[] output) {
double delta = b - a;
if (output.length <= 1) {
output[0] = a;
return;
}
double interval = 1.0 / (output.length - 1);
if (alpha != 0) {
double denom = 1 / (1 - Math.exp(alpha));
for (int i = 0; i < output.length; i++) {
output[i] = a + (1 - Math.exp(i * alpha * interval)) * delta * denom;
}
} else {
for (int i = 0; i < output.length; i++) {
output[i] = a + i * delta * interval;
}
}
}
public static double gen4(Gen g) {
int i;
int points = 0;
int seglen = 0;
double factor;
double time[] = new double[MAX_POINTS];
double value[] = new double[MAX_POINTS];
double alpha[] = new double[MAX_POINTS];
double ptr[];
if (g.nargs < 5 || (g.nargs % 3) != 2) /*
* check number of args
*/ {
System.out.println("gen4 usage: t1 v1 a1 ... tn vn");
}
if ((g.nargs / 3) + 1 > MAX_POINTS) {
System.out.println("gen4 too many arguments");
}
for (i = points = 0; i < g.nargs; points++) {
time[points] = g.pvals[i++];
if (points > 0 && time[points] < time[points - 1]) {
System.out.println("gen4 non-increasing time values");
}
value[points] = g.pvals[i++];
if (i < g.nargs) {
alpha[points] = g.pvals[i++];
}
}
factor = (g.size - 1) / time[points - 1];
for (i = 0; i < points; i++) {
time[i] *= factor;
}
ptr = g.array;
for (i = 0; i < points - 1; i++) {
seglen = (int) (Math.floor(time[i + 1] + 0.5)
- Math.floor(time[i] + 0.5) + 1);
trans(value[i], alpha[i], value[i + 1], seglen, ptr);
ptr[i] += seglen - 1;
}
fnscl(g);
return 0.0;
}
}
In Java, stand alone methods are not allowed. You should make them member of some class. In your case, it seems that 2 of your methods are using class gen as argument fnscl() amd gen4(). You can make them as member methods. The other one can remain static within class.
public class gen{
// data ...
public void fnscl () { ... } // member method
public double gen4 () { ... } // member method
// static method
public static void trans(double a, double alpha, double b, int n, double[] output) { ... }
}
main() also should be part of some class. I leave that choice up to you.
Java is a fully object oriented language in terms of paradigms. (Not as c++ which is also procedural), that's why as Kerrek SB said all methods has to be declared and defined inside a class.
What he was mistaken is that a file can contain only one public class and it has to be named exactly as the file. But it can also contain any number non-public classes with arbitrary names.
To run the program, you have to first compile the file with javac [filename].java then run it with java [classname] without! .class
One more thing. You can't declare a method like this:
public void foo();
The compiler will consider it to be an abstract method and raise an error message.
Related
I was tasked with implementing the nearest neighbour algorithm for the travelling salesman problem. It was said that the method should try starting from every city and return the best tour found. According to the auto-marking program, my implementation works correctly for the most basic case, but only works partially for all more advanced cases.
I don't understand where I went wrong, and am seeking a review of my code for correctness. I am keen to find out where I went wrong and what the correct approach would be.
My Java code is as follows:
/*
* Returns the shortest tour found by exercising the NN algorithm
* from each possible starting city in table.
* table[i][j] == table[j][i] gives the cost of travel between City i and City j.
*/
public static int[] tspnn(double[][] table) {
// number of vertices
int numberOfVertices = table.length;
// the Hamiltonian cycle built starting from vertex i
int[] currentHamiltonianCycle = new int[numberOfVertices];
// the lowest total cost Hamiltonian cycle
double lowestTotalCost = Double.POSITIVE_INFINITY;
// the shortest Hamiltonian cycle
int[] shortestHamiltonianCycle = new int[numberOfVertices];
// consider each vertex i as a starting point
for (int i = 0; i < numberOfVertices; i++) {
/*
* Consider all vertices that are reachable from the starting point i,
* thereby creating a new current Hamiltonian cycle.
*/
for (int j = 0; j < numberOfVertices; j++) {
/*
* The modulo of the sum of i and j allows us to account for the fact
* that Java indexes arrays from 0.
*/
currentHamiltonianCycle[j] = (i + j) % numberOfVertices;
}
for (int j = 1; j < numberOfVertices - 1; j++) {
int nextVertex = j;
for (int p = j + 1; p < numberOfVertices; p++) {
if (table[currentHamiltonianCycle[j - 1]][currentHamiltonianCycle[p]] < table[currentHamiltonianCycle[j - 1]][currentHamiltonianCycle[nextVertex]]) {
nextVertex = p;
}
}
int a = currentHamiltonianCycle[nextVertex];
currentHamiltonianCycle[nextVertex] = currentHamiltonianCycle[j];
currentHamiltonianCycle[j] = a;
}
/*
* Find the total cost of the current Hamiltonian cycle.
*/
double currentTotalCost = table[currentHamiltonianCycle[0]][currentHamiltonianCycle[numberOfVertices - 1]];
for (int z = 0; z < numberOfVertices - 1; z++) {
currentTotalCost += table[currentHamiltonianCycle[z]][currentHamiltonianCycle[z + 1]];
}
if (currentTotalCost < lowestTotalCost) {
lowestTotalCost = currentTotalCost;
shortestHamiltonianCycle = currentHamiltonianCycle;
}
}
return shortestHamiltonianCycle;
}
Edit
I've gone through this code with pen and paper for a simple example, and I can't find any problems with the algorithm implementation. Based on this, it seems to me that it should work in the general case.
Edit 2
I have tested my implementation with the following mock example:
double[][] table = {{0, 2.3, 1.8, 4.5}, {2.3, 0, 0.4, 0.1},
{1.8, 0.4, 0, 1.3}, {4.5, 0.1, 1.3, 0}};
It seems to produce the expected output for the nearest neighbour algorithm, which is 3 -> 1 -> 2 -> 0
I am now wondering whether the auto-marking program is incorrect, or whether it's just that my implementation does not work in the general case.
As I have stated in my comments, I see one basic problem with the algorithm itself:
It will NOT properly permute the towns, but always work in sequence (A-B-C-D-A-B-C-D, start anywhere and take 4)
To prove that problem, I wrote the following code for testing and setting up simple and advanced examples.
Please first configure it via the static public final constants, before you change the code itself.
Focusing on the simple example: if the algorithm worked fine, the result would always be either A-B-C-D or D-C-B-A.
But as you can observe with the output, the algorithm will not select the (globally) best tour, because it does its permutations of tested towns wrong.
I've added in my own Object-Oriented implementation to showcase:
problems with selections, which is really hard to do properly in ONE method all at once
how the OO style has its advantages
that proper testing/developing is quite easy to set up and perform (I'm not even using Unit tests here, that would be the next step to verify/validate algorithms)
Code:
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashSet;
public class TSP_NearestNeighbour {
static public final int NUMBER_OF_TEST_RUNS = 4;
static public final boolean GENERATE_SIMPLE_TOWNS = true;
static public final int NUMBER_OF_COMPLEX_TOWNS = 10;
static public final int DISTANCE_RANGE_OF_COMPLEX_TOWNS = 100;
static private class Town {
public final String Name;
public final int X;
public final int Y;
public Town(final String pName, final int pX, final int pY) {
Name = pName;
X = pX;
Y = pY;
}
public double getDistanceTo(final Town pOther) {
final int dx = pOther.X - X;
final int dy = pOther.Y - Y;
return Math.sqrt(Math.abs(dx * dx + dy * dy));
}
#Override public int hashCode() { // not really needed here
final int prime = 31;
int result = 1;
result = prime * result + X;
result = prime * result + Y;
return result;
}
#Override public boolean equals(final Object obj) {
if (this == obj) return true;
if (obj == null) return false;
if (getClass() != obj.getClass()) return false;
final Town other = (Town) obj;
if (X != other.X) return false;
if (Y != other.Y) return false;
return true;
}
#Override public String toString() {
return Name + " (" + X + "/" + Y + ")";
}
}
static private double[][] generateDistanceTable(final ArrayList<Town> pTowns) {
final double[][] ret = new double[pTowns.size()][pTowns.size()];
for (int outerIndex = 0; outerIndex < pTowns.size(); outerIndex++) {
final Town outerTown = pTowns.get(outerIndex);
for (int innerIndex = 0; innerIndex < pTowns.size(); innerIndex++) {
final Town innerTown = pTowns.get(innerIndex);
final double distance = outerTown.getDistanceTo(innerTown);
ret[outerIndex][innerIndex] = distance;
}
}
return ret;
}
static private ArrayList<Town> generateTowns_simple() {
final Town a = new Town("A", 0, 0);
final Town b = new Town("B", 1, 0);
final Town c = new Town("C", 2, 0);
final Town d = new Town("D", 3, 0);
return new ArrayList<>(Arrays.asList(a, b, c, d));
}
static private ArrayList<Town> generateTowns_complex() {
final ArrayList<Town> allTowns = new ArrayList<>();
for (int i = 0; i < NUMBER_OF_COMPLEX_TOWNS; i++) {
final int randomX = (int) (Math.random() * DISTANCE_RANGE_OF_COMPLEX_TOWNS);
final int randomY = (int) (Math.random() * DISTANCE_RANGE_OF_COMPLEX_TOWNS);
final Town t = new Town("Town-" + (i + 1), randomX, randomY);
if (allTowns.contains(t)) { // do not allow different towns at same location!
System.out.println("Towns colliding at " + t);
--i;
} else {
allTowns.add(t);
}
}
return allTowns;
}
static private ArrayList<Town> generateTowns() {
if (GENERATE_SIMPLE_TOWNS) return generateTowns_simple();
else return generateTowns_complex();
}
static private void printTowns(final ArrayList<Town> pTowns, final double[][] pDistances) {
System.out.println("Towns:");
for (final Town town : pTowns) {
System.out.println("\t" + town);
}
System.out.println("Distance Matrix:");
for (int y = 0; y < pDistances.length; y++) {
System.out.print("\t");
for (int x = 0; x < pDistances.length; x++) {
System.out.print(pDistances[y][x] + " (" + pTowns.get(y).Name + "-" + pTowns.get(x).Name + ")" + "\t");
}
System.out.println();
}
}
private static void testAlgorithm() {
final ArrayList<Town> towns = generateTowns();
for (int i = 0; i < NUMBER_OF_TEST_RUNS; i++) {
final double[][] distances = generateDistanceTable(towns);
printTowns(towns, distances);
{
final int[] path = tspnn(distances);
System.out.println("tspnn Path:");
for (int pathIndex = 0; pathIndex < path.length; pathIndex++) {
final Town t = towns.get(pathIndex);
System.out.println("\t" + t);
}
}
{
final ArrayList<Town> path = tspnn_simpleNN(towns);
System.out.println("tspnn_simpleNN Path:");
for (final Town t : path) {
System.out.println("\t" + t);
}
System.out.println("\n");
}
// prepare for for next run. We do this at the end of the loop so we can only print first config
Collections.shuffle(towns);
}
}
public static void main(final String[] args) {
testAlgorithm();
}
/*
* Returns the shortest tour found by exercising the NN algorithm
* from each possible starting city in table.
* table[i][j] == table[j][i] gives the cost of travel between City i and City j.
*/
public static int[] tspnn(final double[][] table) {
// number of vertices
final int numberOfVertices = table.length;
// the Hamiltonian cycle built starting from vertex i
final int[] currentHamiltonianCycle = new int[numberOfVertices];
// the lowest total cost Hamiltonian cycle
double lowestTotalCost = Double.POSITIVE_INFINITY;
// the shortest Hamiltonian cycle
int[] shortestHamiltonianCycle = new int[numberOfVertices];
// consider each vertex i as a starting point
for (int i = 0; i < numberOfVertices; i++) {
/*
* Consider all vertices that are reachable from the starting point i,
* thereby creating a new current Hamiltonian cycle.
*/
for (int j = 0; j < numberOfVertices; j++) {
/*
* The modulo of the sum of i and j allows us to account for the fact
* that Java indexes arrays from 0.
*/
currentHamiltonianCycle[j] = (i + j) % numberOfVertices;
}
for (int j = 1; j < numberOfVertices - 1; j++) {
int nextVertex = j;
for (int p = j + 1; p < numberOfVertices; p++) {
if (table[currentHamiltonianCycle[j - 1]][currentHamiltonianCycle[p]] < table[currentHamiltonianCycle[j - 1]][currentHamiltonianCycle[nextVertex]]) {
nextVertex = p;
}
}
final int a = currentHamiltonianCycle[nextVertex];
currentHamiltonianCycle[nextVertex] = currentHamiltonianCycle[j];
currentHamiltonianCycle[j] = a;
}
/*
* Find the total cost of the current Hamiltonian cycle.
*/
double currentTotalCost = table[currentHamiltonianCycle[0]][currentHamiltonianCycle[numberOfVertices - 1]];
for (int z = 0; z < numberOfVertices - 1; z++) {
currentTotalCost += table[currentHamiltonianCycle[z]][currentHamiltonianCycle[z + 1]];
}
if (currentTotalCost < lowestTotalCost) {
lowestTotalCost = currentTotalCost;
shortestHamiltonianCycle = currentHamiltonianCycle;
}
}
return shortestHamiltonianCycle;
}
/**
* Here come my basic implementations.
* They can be heavily (heavily!) improved, but are verbose and direct to show the logic behind them
*/
/**
* <p>example how to implement the NN solution th OO way</p>
* we could also implement
* <ul>
* <li>a recursive function</li>
* <li>or one with running counters</li>
* <li>or one with a real map/route objects, where further optimizations can take place</li>
* </ul>
*/
public static ArrayList<Town> tspnn_simpleNN(final ArrayList<Town> pTowns) {
ArrayList<Town> bestRoute = null;
double bestCosts = Double.MAX_VALUE;
for (final Town startingTown : pTowns) {
//setup
final ArrayList<Town> visitedTowns = new ArrayList<>(); // ArrayList because we need a stable index
final HashSet<Town> unvisitedTowns = new HashSet<>(pTowns); // all towns are available at start; we use HashSet because we need fast search; indexing plays not role here
// step 1
Town currentTown = startingTown;
visitedTowns.add(currentTown);
unvisitedTowns.remove(currentTown);
// steps 2-n
while (unvisitedTowns.size() > 0) {
// find nearest town
final Town nearestTown = findNearestTown(currentTown, unvisitedTowns);
if (nearestTown == null) throw new IllegalStateException("Something in the code is wrong...");
currentTown = nearestTown;
visitedTowns.add(currentTown);
unvisitedTowns.remove(currentTown);
}
// selection
final double cost = getCostsOfRoute(visitedTowns);
if (cost < bestCosts) {
bestCosts = cost;
bestRoute = visitedTowns;
}
}
return bestRoute;
}
static private Town findNearestTown(final Town pCurrentTown, final HashSet<Town> pSelectableTowns) {
double minDist = Double.MAX_VALUE;
Town minTown = null;
for (final Town checkTown : pSelectableTowns) {
final double dist = pCurrentTown.getDistanceTo(checkTown);
if (dist < minDist) {
minDist = dist;
minTown = checkTown;
}
}
return minTown;
}
static private double getCostsOfRoute(final ArrayList<Town> pTowns) {
double costs = 0;
for (int i = 1; i < pTowns.size(); i++) { // use pre-index
final Town t1 = pTowns.get(i - 1);
final Town t2 = pTowns.get(i);
final double cost = t1.getDistanceTo(t2);
costs += cost;
}
return costs;
}
}
This, at an unchanged state, gives us outputs similar to the following:
Towns:
A (0/0)
B (1/0)
C (2/0)
D (3/0)
Distance Matrix:
0.0 (A-A) 1.0 (A-B) 2.0 (A-C) 3.0 (A-D)
1.0 (B-A) 0.0 (B-B) 1.0 (B-C) 2.0 (B-D)
2.0 (C-A) 1.0 (C-B) 0.0 (C-C) 1.0 (C-D)
3.0 (D-A) 2.0 (D-B) 1.0 (D-C) 0.0 (D-D)
tspnn Path:
A (0/0)
B (1/0)
C (2/0)
D (3/0)
tspnn_simpleNN Path:
A (0/0)
B (1/0)
C (2/0)
D (3/0)
Towns:
C (2/0)
D (3/0)
B (1/0)
A (0/0)
Distance Matrix:
0.0 (C-C) 1.0 (C-D) 1.0 (C-B) 2.0 (C-A)
1.0 (D-C) 0.0 (D-D) 2.0 (D-B) 3.0 (D-A)
1.0 (B-C) 2.0 (B-D) 0.0 (B-B) 1.0 (B-A)
2.0 (A-C) 3.0 (A-D) 1.0 (A-B) 0.0 (A-A)
tspnn Path:
C (2/0)
D (3/0)
B (1/0)
A (0/0)
tspnn_simpleNN Path:
D (3/0)
C (2/0)
B (1/0)
A (0/0)
Towns:
D (3/0)
B (1/0)
C (2/0)
A (0/0)
Distance Matrix:
0.0 (D-D) 2.0 (D-B) 1.0 (D-C) 3.0 (D-A)
2.0 (B-D) 0.0 (B-B) 1.0 (B-C) 1.0 (B-A)
1.0 (C-D) 1.0 (C-B) 0.0 (C-C) 2.0 (C-A)
3.0 (A-D) 1.0 (A-B) 2.0 (A-C) 0.0 (A-A)
tspnn Path:
D (3/0)
B (1/0)
C (2/0)
A (0/0)
tspnn_simpleNN Path:
D (3/0)
C (2/0)
B (1/0)
A (0/0)
Towns:
A (0/0)
B (1/0)
C (2/0)
D (3/0)
Distance Matrix:
0.0 (A-A) 1.0 (A-B) 2.0 (A-C) 3.0 (A-D)
1.0 (B-A) 0.0 (B-B) 1.0 (B-C) 2.0 (B-D)
2.0 (C-A) 1.0 (C-B) 0.0 (C-C) 1.0 (C-D)
3.0 (D-A) 2.0 (D-B) 1.0 (D-C) 0.0 (D-D)
tspnn Path:
A (0/0)
B (1/0)
C (2/0)
D (3/0)
tspnn_simpleNN Path:
A (0/0)
B (1/0)
C (2/0)
D (3/0)
As you can see, your algorithm is severely dependent on the sequence of input/towns. If the algorithm was correct, the result would always be A-B-C-D or D-C-B-A.
So use this 'testing' framework to improve your code. The method you provided tspnn() does not rely on the other code, so once you improved your code, you can comment out all my stuff. Or put this all in another class, and call your real implementation across classes. As it's static public, you can easily call it via YourClassName.tspnn(distances).
On the other hand, maybe see if you can improve the auto-marking program, so you can go full Java without problems.
Question:
A class SeriesSum is designed to calculate the sum of the following series:
Class name : SeriesSum
Data members/instance variables:
x : to store an integer number
n : to store number of terms
sum : double variable to store the sum of the series
Member functions:
SeriesSum(int xx, int nn) : constructor to assign x=xx and n=nn
double findfact(int m) to return the factorial of m using recursive
technique.
double findpower(int x, int y) : to return x raised to the power of y using
recursive technique.
void calculate( ) : to calculate the sum of the series by invoking
the recursive functions respectively
void display( ) : to display the sum of the series
(a) Specify the class SeriesSum, giving details of the constructor(int, int),
double findfact(int), double findpower(int, int), void calculate( ) and
void display( ).
Define the main( ) function to create an object and call the
functions accordingly to enable the task.
Code:
class SeriesSum
{
int x,n;
double sum;
SeriesSum(int xx,int nn)
{ x=xx;
n=nn;
sum=0.0;
}
double findfact(int a)
{ return (a<2)? 1:a*findfact(a-1);
}
double findpower(int a, int b)
{ return (b==0)? 1:a*findpower(a,b-1);
}
void calculate()
{ for(int i=2;i<=n;i+=2)
sum += findpower(x,i)/findfact(i-1);
}
void display()
{ System.out.println("sum="+ sum);
}
static void main()
{ SeriesSum obj = new SeriesSum(3,8);
obj.calculate();
obj.display();
}
}
MyProblem:
I am having problems in understanding that when i= any odd number (Taking an example such as 3 here)then it value that passes through findfact is (i-1)=2 then how am I getting the odd factorials such as 3!
Any help or guidance would be highly appreciated.
Optional:
If you can somehow explain the recursion taking place in the findpower and findfactorial,it would be of great help.
Take a closer look a the loop. i starts at 2 and is incremented by 2 every iteration, so it is never odd. It corresponds to the successive powers of x, each of which is divided by the factorial of i -1 (which IS odd).
As for the recursion in findfact, you just need to unwrap the first few calls by hand to see why it works :
findfact(a) = a * findfact(a -1)
= a * (a - 1) * findfact(a -2)
= a * (a - 1) * (a - 2) * findfact(a - 3)
...
= a * (a - 1) * (a - 2) * ... * 2 * findfact(1)
= a * (a - 1) * (a - 2) * ... * 2 * 1
= a!*
The same reasoning works with findpower.
As a side note, while it may be helpful for teaching purposes, recursion is a terrible idea for computing factorials or powers.
I'm not sure I understand your question correctly, but I try to help you the best I can.
I am having problems in understanding that when i= any odd number
In this code i never will be any odd number
for(int i=2;i<=n;i+=2)
i will be: 2 , 4 , 6 , 8 and so on because i+=2
The Recursion
The findfact() function in a more readable version:
double findfact(int a){
if(a < 2 ){
return 1;
} else {
return a * findfact(a - 1);
}
}
you can imagine it as a staircase, every call of findfact is a step:
We test: if a < 2 then return 1 else we call findfact() again with a-1 and multiply a with the result of findfact()
The same function without recursion:
double findfact(int a){
int sum = 1;
for(int i = a; i > 0; i--){
sum *= i;
}
return sum;
}
Same by the findpower function:
if b == 0 then return 1 else call findpower() with a, b-1 and multiply the return value of findpower() with a
So the last called findpower() will return 1 (b = 0)
The second last findpower() will return a * 1 (b = 1)
The third last findpower() will return a * a * 1 (b = 2)
so you can see findpower(a, 2) = a * a * 1 = a^2
Hope I could help you
Try to run below code, it will clear all your doubts (i have modified some access specifier and created main method)
public class SeriesSum
{
int x,n;
double sum;
SeriesSum(int xx,int nn)
{ x=xx;
n=nn;
sum=0.0;
}
double findfact(int a)
{ return (a<2)? 1:a*findfact(a-1);
}
double findpower(int a, int b)
{ return (b==0)? 1:a*findpower(a,b-1);
}
void calculate()
{
System.out.println("x ="+x);
System.out.println("n ="+n);
for(int i=2;i<=n;i+=2){
System.out.println(x+"^"+i+"/"+(i-1)+"!" +" = " +(findpower(x,i)+"/"+findfact(i-1)) );
//System.out.println(findpower(x,i)+"/"+findfact(i-1));
sum += findpower(x,i)/findfact(i-1);
}
}
void display()
{ System.out.println("sum="+ sum);
}
public static void main(String arg[])
{ SeriesSum obj = new SeriesSum(3,8);
obj.calculate();
obj.display();
}
}
// ----- output ----
x =3
n =8
3^2/1! = 9.0/1.0
3^4/3! = 81.0/6.0
3^6/5! = 729.0/120.0
3^8/7! = 6561.0/5040.0
sum=29.876785714285713
You can simplify the summation and get rid of power and factorial. Please notice:
The very first term is just x * x
If you know term item == x ** (2 * n) / (2 * n - 1)! the next one will be item * x * x / (2 * n) / (2 * n + 1).
Implementation:
private static double sum(double x, int count) {
double item = x * x; // First item
double result = item;
for (int i = 1; i <= count; ++i) {
// Next item from previous
item = item * x * x / (2 * i) / (2 * i +1);
result += item;
}
return result;
}
In the real world, you can notice that
sinh(x) = x/1! + x**3/3! + x**5/5! + ... + x**(2*n - 1) / (2*n - 1)! + ...
and your serie is nothing but
x * sinh(x) = x**2/1! + x**4 / 3! + ... + x**(2*n) / (2*n - 1)! + ...
So you can implement
private static double sum(double x) {
return x * (Math.exp(x) - Math.exp(-x)) / 2.0;
}
I got bored and decided to dive into remaking the square root function without referencing any of the Math.java functions. I have gotten to this point:
package sqrt;
public class SquareRoot {
public static void main(String[] args) {
System.out.println(sqrtOf(8));
}
public static double sqrtOf(double n){
double x = log(n,2);
return powerOf(2, x/2);
}
public static double log(double n, double base)
{
return (Math.log(n)/Math.log(base));
}
public static double powerOf(double x, double y) {
return powerOf(e(),y * log(x, e()));
}
public static int factorial(int n){
if(n <= 1){
return 1;
}else{
return n * factorial((n-1));
}
}
public static double e(){
return 1/factorial(1);
}
public static double e(int precision){
return 1/factorial(precision);
}
}
As you may very well see, I came to the point in my powerOf() function that infinitely recalls itself. I could replace that and use Math.exp(y * log(x, e()), so I dived into the Math source code to see how it handled my problem, resulting in a goose chase.
public static double exp(double a) {
return StrictMath.exp(a); // default impl. delegates to StrictMath
}
which leads to:
public static double exp(double x)
{
if (x != x)
return x;
if (x > EXP_LIMIT_H)
return Double.POSITIVE_INFINITY;
if (x < EXP_LIMIT_L)
return 0;
// Argument reduction.
double hi;
double lo;
int k;
double t = abs(x);
if (t > 0.5 * LN2)
{
if (t < 1.5 * LN2)
{
hi = t - LN2_H;
lo = LN2_L;
k = 1;
}
else
{
k = (int) (INV_LN2 * t + 0.5);
hi = t - k * LN2_H;
lo = k * LN2_L;
}
if (x < 0)
{
hi = -hi;
lo = -lo;
k = -k;
}
x = hi - lo;
}
else if (t < 1 / TWO_28)
return 1;
else
lo = hi = k = 0;
// Now x is in primary range.
t = x * x;
double c = x - t * (P1 + t * (P2 + t * (P3 + t * (P4 + t * P5))));
if (k == 0)
return 1 - (x * c / (c - 2) - x);
double y = 1 - (lo - x * c / (2 - c) - hi);
return scale(y, k);
}
Values that are referenced:
LN2 = 0.6931471805599453, // Long bits 0x3fe62e42fefa39efL.
LN2_H = 0.6931471803691238, // Long bits 0x3fe62e42fee00000L.
LN2_L = 1.9082149292705877e-10, // Long bits 0x3dea39ef35793c76L.
INV_LN2 = 1.4426950408889634, // Long bits 0x3ff71547652b82feL.
INV_LN2_H = 1.4426950216293335, // Long bits 0x3ff7154760000000L.
INV_LN2_L = 1.9259629911266175e-8; // Long bits 0x3e54ae0bf85ddf44L.
P1 = 0.16666666666666602, // Long bits 0x3fc555555555553eL.
P2 = -2.7777777777015593e-3, // Long bits 0xbf66c16c16bebd93L.
P3 = 6.613756321437934e-5, // Long bits 0x3f11566aaf25de2cL.
P4 = -1.6533902205465252e-6, // Long bits 0xbebbbd41c5d26bf1L.
P5 = 4.1381367970572385e-8, // Long bits 0x3e66376972bea4d0L.
TWO_28 = 0x10000000, // Long bits 0x41b0000000000000L
Here is where I'm starting to get lost. But I can make a few assumptions that so far the answer is starting to become estimated. I then find myself here:
private static double scale(double x, int n)
{
if (Configuration.DEBUG && abs(n) >= 2048)
throw new InternalError("Assertion failure");
if (x == 0 || x == Double.NEGATIVE_INFINITY
|| ! (x < Double.POSITIVE_INFINITY) || n == 0)
return x;
long bits = Double.doubleToLongBits(x);
int exp = (int) (bits >> 52) & 0x7ff;
if (exp == 0) // Subnormal x.
{
x *= TWO_54;
exp = ((int) (Double.doubleToLongBits(x) >> 52) & 0x7ff) - 54;
}
exp += n;
if (exp > 0x7fe) // Overflow.
return Double.POSITIVE_INFINITY * x;
if (exp > 0) // Normal.
return Double.longBitsToDouble((bits & 0x800fffffffffffffL)
| ((long) exp << 52));
if (exp <= -54)
return 0 * x; // Underflow.
exp += 54; // Subnormal result.
x = Double.longBitsToDouble((bits & 0x800fffffffffffffL)
| ((long) exp << 52));
return x * (1 / TWO_54);
}
TWO_54 = 0x40000000000000L
While I am, I would say, very understanding of math and programming, I hit the point to where I find myself at a Frankenstein monster mix of the two. I noticed the intrinsic switch to bits (which I have little to no experience with), and I was hoping someone could explain to me the processes that are occurring "under the hood" so to speak. Specifically where I got lost is from "Now x is in primary range" in the exp() method on wards and what the values that are being referenced really represent. I'm was asking for someone to help me understand not only the methods themselves, but also how they arrive to the answer. Feel free to go as in depth as needed.
edit:
if someone could maybe make this tag: "strictMath" that would be great. I believe that its size and for the Math library deriving from it justifies its existence.
To the exponential function:
What happens is that
exp(x) = 2^k * exp(x-k*log(2))
is exploited for positive x. Some magic is used to get more consistent results for large x where the reduction x-k*log(2) will introduce cancellation errors.
On the reduced x a rational approximation with minimized maximal error over the interval 0.5..1.5 is used, see Pade approximations and similar. This is based on the symmetric formula
exp(x) = exp(x/2)/exp(-x/2) = (c(x²)+x)/(c(x²)-x)
(note that the c in the code is x+c(x)-2). When using Taylor series, approximations for c(x*x)=x*coth(x/2) are based on
c(u)=2 + 1/6*u - 1/360*u^2 + 1/15120*u^3 - 1/604800*u^4 + 1/23950080*u^5 - 691/653837184000*u^6
The scale(x,n) function implements the multiplication x*2^n by directly manipulating the exponent in the bit assembly of the double floating point format.
Computing square roots
To compute square roots it would be more advantageous to compute them directly. First reduce the interval of approximation arguments via
sqrt(x)=2^k*sqrt(x/4^k)
which can again be done efficiently by directly manipulating the bit format of double.
After x is reduced to the interval 0.5..2.0 one can then employ formulas of the form
u = (x-1)/(x+1)
y = (c(u*u)+u) / (c(u*u)-u)
based on
sqrt(x)=sqrt(1+u)/sqrt(1-u)
and
c(v) = 1+sqrt(1-v) = 2 - 1/2*v - 1/8*v^2 - 1/16*v^3 - 5/128*v^4 - 7/256*v^5 - 21/1024*v^6 - 33/2048*v^7 - ...
In a program without bit manipulations this could look like
double my_sqrt(double x) {
double c,u,v,y,scale=1;
int k=0;
if(x<0) return NaN;
while(x>2 ) { x/=4; scale *=2; k++; }
while(x<0.5) { x*=4; scale /=2; k--; }
// rational approximation of sqrt
u = (x-1)/(x+1);
v = u*u;
c = 2 - v/2*(1 + v/4*(1 + v/2));
y = 1 + 2*u/(c-u); // = (c+u)/(c-u);
// one Halley iteration
y = y*(1+8*x/(3*(3*y*y+x))) // = y*(y*y+3*x)/(3*y*y+x)
// reconstruct original scale
return y*scale;
}
One could replace the Halley step with two Newton steps, or
with a better uniform approximation in c one could replace the Halley step with one Newton step, or ...
I'm working on euler problem 14 (http://projecteuler.net/problem=14). I've tried to tackle it by having a method which runs through the collatz equations, and returns the number of steps taken. If it's higher then the current record it overwrites it, otherwise it moves on to the next integer. It was giving stack overflow errors so I added the system.out.println messages to try and identify where it was stalling, and currently it dies whenever it reaches 5200~, I'm confused as to why, because as far as i can tell no values encountered at this point should go over the int limit, and the error persisted even if i changed "numberStorage" from int to long.
Here is my current code:
/**
* Write a description of class calculator here.
*
* #author (your name)
* #version (a version number or a date)
*/
public class Calculator
{
// instance variables - replace the example below with your own
private int x;
private int startingNumber = 1;
private int stepCount;
private int numberStorage;
private int currentRecordStart;
private int currentRecordSteps = 0;
/**
* a string and int value to track multiple starting numbers with the same number of steps
*/
private String tieNote = "no ties";
private int multiTie = 0;
/**
* Constructor for objects of class calculator
*/
public Calculator()
{
x = 0;
}
/**
* begins function
*/
public void initiater()
{
numberStorage = 0;
stepCount = 0;
startingNumber = 1;
currentRecordStart = 1;
currentRecordSteps = 0;
stepCount = 0;
recordHolder(1,1);
}
/**
* starts next rotation
*/
public void steprunner()
{
++startingNumber;
System.out.println("starting rotation " + startingNumber + " current record " + currentRecordSteps);
stepCount = 0;
numberStorage = 0;
recordHolder(startingNumber, collatzSequence(startingNumber));
}
/**
* Runs collatz sequence and updates a variable with the number of steps.
*/
public int collatzSequence(int N)
{
numberStorage = 0;
numberStorage = N;
if (N == 1)
{
return stepCount;
}
else if ( (N & 1) == 0)
{
numberStorage = numberStorage / 2;
++stepCount;
return collatzSequence(numberStorage);
}
else if ( (N & 1) != 0)
{
numberStorage = 3 * numberStorage + 1;
++stepCount;
numberStorage = numberStorage / 2;
++stepCount;
return collatzSequence(numberStorage);
}
return stepCount;
}
/**
* stores record and starts next cycle
*/
public void recordHolder(int startingnumber, int stepcount)
{
if (startingNumber <= 999999)
{
if (stepcount > currentRecordSteps)
{
currentRecordSteps = stepcount;
currentRecordStart = startingnumber;
tieNote = "no ties";
multiTie = 0;
System.out.println("a tie occured!");
}
else if (stepcount == currentRecordSteps)
{
tieNote = ("starting number " + startingnumber + " also had " + stepcount + "steps");
++multiTie;
System.out.println("a secondary tie occured!");
}
steprunner();
}
if (startingNumber == 999999)
{
simulationEnder();
}
}
/**
* ends simulation
*/
public void simulationEnder()
{
System.out.println("the number with the highest number of steps was " + currentRecordStart +
" with " + currentRecordSteps + " steps!");
}
}
I'm not going to read your code. But I can show you a solution, written in pseudocode, that is simple and quick:
function euler14(n):
cs := makeArray(1..n)
maxX, maxLen, cs[1] := 1, 1, 1
for k from 2 to n
c, s := 0, k
while k <= s
if s % 2 == 0
s := s / 2
else
s := 3 * s + 1
c := c + 1
cs[k] := cs[s] + c
if maxLen < xs[k]
maxX, maxLen := k, cs[k]
return maxX
The trick is to calculate and save the values of the lengths of the collatz chain, in order starting from 1; then, if a future sequence drops below its starting point, calculation stops in favor of a simple lookup. Here the cs array is the cache, k is the index of the chain that is currently being computed, s is the current item in the chain, and c is the current length of the chain. Computing euler14(1000000) should take no more than a second or two.
So what I'm trying to do is convert double to rational number. I check how many digits there is after decimal point and I want to save the number 123.456 as 123456 / 1000, for example.
public Rational(double d){
String s = String.valueOf(d);
int digitsDec = s.length() - 1 - s.indexOf('.');
for(int i = 0; i < digitsDec; i++){
d *= 10;
}
System.out.println((int)d); //checking purposes
}
However, for the number 123.456 I get a round off error and the result is 123455. I guess it'd be possible to fix this with BigDecimal but I can't get it to work. Also, having calculated what rational number it would be, I would like to call another constructor with parameters (int numerator, int denominator) but I can't obviously call the constructor in the line where println is now. How should I do this?
For the first part of the question, Java is storing .6 as .5999999 (repeating). See this output:
(after first multiply): d=1234.56
(after second multiply): d=12345.599999999999
(after third multiply): d=123455.99999999999
One fix is to use d = Math.round(d) immediately after your loop finishes.
public class Rational {
private int num, denom;
public Rational(double d) {
String s = String.valueOf(d);
int digitsDec = s.length() - 1 - s.indexOf('.');
int denom = 1;
for(int i = 0; i < digitsDec; i++){
d *= 10;
denom *= 10;
}
int num = (int) Math.round(d);
this.num = num; this.denom = denom;
}
public Rational(int num, int denom) {
this.num = num; this.denom = denom;
}
public String toString() {
return String.valueOf(num) + "/" + String.valueOf(denom);
}
public static void main(String[] args) {
System.out.println(new Rational(123.456));
}
}
It works - try it.
For the second part of your question...
In order to call the second constructor from the first, you can use the "this" keyword
this(num, denom)
But it has to be the very first line in the constructor... which doesn't make sense here (we have to do some calculations first). So I wouldn't bother trying to do that.
This code may be overkill for you, but it deals with the rounding error that you're experiencing, and it also takes care of repeating decimals (4.99999999999999 turns into 5, and 0.33333333333333333333 turns into 1/3).
public static Rational toRational(double number){
return toRational(number, 8);
}
public static Rational toRational(double number, int largestRightOfDecimal){
long sign = 1;
if(number < 0){
number = -number;
sign = -1;
}
final long SECOND_MULTIPLIER_MAX = (long)Math.pow(10, largestRightOfDecimal - 1);
final long FIRST_MULTIPLIER_MAX = SECOND_MULTIPLIER_MAX * 10L;
final double ERROR = Math.pow(10, -largestRightOfDecimal - 1);
long firstMultiplier = 1;
long secondMultiplier = 1;
boolean notIntOrIrrational = false;
long truncatedNumber = (long)number;
Rational rationalNumber = new Rational((long)(sign * number * FIRST_MULTIPLIER_MAX), FIRST_MULTIPLIER_MAX);
double error = number - truncatedNumber;
while( (error >= ERROR) && (firstMultiplier <= FIRST_MULTIPLIER_MAX)){
secondMultiplier = 1;
firstMultiplier *= 10;
while( (secondMultiplier <= SECOND_MULTIPLIER_MAX) && (secondMultiplier < firstMultiplier) ){
double difference = (number * firstMultiplier) - (number * secondMultiplier);
truncatedNumber = (long)difference;
error = difference - truncatedNumber;
if(error < ERROR){
notIntOrIrrational = true;
break;
}
secondMultiplier *= 10;
}
}
if(notIntOrIrrational){
rationalNumber = new Rational(sign * truncatedNumber, firstMultiplier - secondMultiplier);
}
return rationalNumber;
}
This provides the following results (results from test cases are shown as comments):
Rational.toRational(110.0/3.0); // 110/3
Rational.toRational(11.0/1000.0); // 11/1000
Rational.toRational(17357.0/33300.0); // 17357/33300
Rational.toRational(215.0/21.0); // 215/21
Rational.toRational(0.123123123123123123123123); // 41/333
Rational.toRational(145731.0/27100.0); // 145731/27100
Rational.toRational(Math.PI); // 62831853/20000000
Rational.toRational(62.0/63.0); // 62/63
Rational.toRational(24.0/25.0); // 24/25
Rational.toRational(-24.0/25.0); //-24/25
Rational.toRational(-0.25333333333333333333333); // -19/75
Rational.toRational(-4.9999999999999999999999); // -5
Rational.toRational(4.9999999999999999999999); // 5
Rational.toRational(123.456); // 15432/125
It's not elegant, however, I believe this does what you're asking.
double a = 123.456;
String aString = Double.toString(a);
String[] fraction = aString.split("\\.");
int denominator = (int)Math.pow(10, fraction[1].length());
int numerator = Integer.parseInt(fraction[0] + "" + fraction[1]);
System.out.println(numerator + "/" + denominator);
Here, d=123.456 then num=123456, j=1000.
/**
* This method calculates a rational number from a double.
* The denominator will always be a multiple of 10.
*
* #param d the double to calculate the fraction from.
* #return the result as Pair of <numerator , denominator>.
*/
private static Pair<Integer,Integer> calculateRational(double d){
int j=1, num;
do{
j=j*10;
}while((d *j)%10!=0);
j=j/10;
num=(int)(d*j);
return new Pair<>(num,j);
}
Here're some tests:
#Test
public void testCalculateRational() {
Assert.assertEquals(new Pair<>(124567, 1000), calculateRational(124.567));
Assert.assertEquals(new Pair<>(12456, 100), calculateRational(124.56));
Assert.assertEquals(new Pair<>(56, 100), calculateRational(0.56));
}
Try
for(int i = 0; i <= digitsDec; i++){
}