Perlin noise value range - java

I used perlin noise to generate a 2D height map. At first i tried some parameters manually and found a good combination of amplitude, persistence,... for my job.
Now that i'm developing the program, i added the feature for user to change the map parameters and make a new map for himself but now i see that for certain parameters (Mostly octaves and frequency) the values are not in the range i used to see. I thought that if a set Amplitude = 20, the values(heights) i get from it will be in e.g [0,20] or [-10,10] or [-20,20] ranges but now i see that Amplitude is not the only parameter that controls output range.
My question is: Is there an exact mathematical formula (a function of Amplitude, Octaves, Frequency and persistence) to compute the range or i should take a lot of samples (like 100,000) and check minimum and maximum values of them to guess the aproximate range?
Note: The following code is an implementation of perlin noise that one of stackoverflow guys worte it in C and i ported it to java.
PerlinNoiseParameters.java
public class PerlinNoiseParameters {
public double persistence;
public double frequency;
public double amplitude;
public int octaves;
public int randomseed;
public PerlinNoiseParameters(double persistence, double frequency, double amplitude, int octaves, int randomseed) {
this.ChangeParameters(persistence, frequency, amplitude, octaves, randomseed);
}
public void ChangeParameters(double persistence, double frequency, double amplitude, int octaves, int randomseed) {
this.persistence = persistence;
this.frequency = frequency;
this.amplitude = amplitude;
this.octaves = octaves;
this.randomseed = 2 + randomseed * randomseed;
}
}
PerlinNoiseGenerator.java
public class PerlinNoiseGenerator {
PerlinNoiseParameters parameters;
public PerlinNoiseGenerator() {
}
public PerlinNoiseGenerator(PerlinNoiseParameters parameters) {
this.parameters = parameters;
}
public void ChangeParameters(double persistence, double frequency, double amplitude, int octaves, int randomseed) {
parameters.ChangeParameters(persistence, frequency, amplitude, octaves, randomseed);
}
public void ChangeParameters(PerlinNoiseParameters newParams) {
parameters = newParams;
}
public double get(double x, double y) {
return parameters.amplitude * Total(x, y);
}
private double Total(double i, double j) {
double t = 0.0f;
double _amplitude = 1;
double freq = parameters.frequency;
for (int k = 0; k < parameters.octaves; k++) {
t += GetValue(j * freq + parameters.randomseed, i * freq + parameters.randomseed)
* _amplitude;
_amplitude *= parameters.persistence;
freq *= 2;
}
return t;
}
private double GetValue(double x, double y) {
int Xint = (int) x;
int Yint = (int) y;
double Xfrac = x - Xint;
double Yfrac = y - Yint;
double n01 = Noise(Xint - 1, Yint - 1);
double n02 = Noise(Xint + 1, Yint - 1);
double n03 = Noise(Xint - 1, Yint + 1);
double n04 = Noise(Xint + 1, Yint + 1);
double n05 = Noise(Xint - 1, Yint);
double n06 = Noise(Xint + 1, Yint);
double n07 = Noise(Xint, Yint - 1);
double n08 = Noise(Xint, Yint + 1);
double n09 = Noise(Xint, Yint);
double n12 = Noise(Xint + 2, Yint - 1);
double n14 = Noise(Xint + 2, Yint + 1);
double n16 = Noise(Xint + 2, Yint);
double n23 = Noise(Xint - 1, Yint + 2);
double n24 = Noise(Xint + 1, Yint + 2);
double n28 = Noise(Xint, Yint + 2);
double n34 = Noise(Xint + 2, Yint + 2);
double x0y0 = 0.0625 * (n01 + n02 + n03 + n04) + 0.1250
* (n05 + n06 + n07 + n08) + 0.2500 * n09;
double x1y0 = 0.0625 * (n07 + n12 + n08 + n14) + 0.1250
* (n09 + n16 + n02 + n04) + 0.2500 * n06;
double x0y1 = 0.0625 * (n05 + n06 + n23 + n24) + 0.1250
* (n03 + n04 + n09 + n28) + 0.2500 * n08;
double x1y1 = 0.0625 * (n09 + n16 + n28 + n34) + 0.1250
* (n08 + n14 + n06 + n24) + 0.2500 * n04;
double v1 = Interpolate(x0y0, x1y0, Xfrac);
double v2 = Interpolate(x0y1, x1y1, Xfrac);
double fin = Interpolate(v1, v2, Yfrac);
return fin;
}
private double Interpolate(double x, double y, double a) {
double negA = 1.0 - a;
double negASqr = negA * negA;
double fac1 = 3.0 * (negASqr) - 2.0 * (negASqr * negA);
double aSqr = a * a;
double fac2 = 3.0 * aSqr - 2.0 * (aSqr * a);
return x * fac1 + y * fac2;
}
private double Noise(int x, int y) {
int n = x + y * 57;
n = (n << 13) ^ n;
int t = (n * (n * n * 15731 + 789221) + 1376312589) & 0x7fffffff;
return 1.0 - (double) t * 0.931322574615478515625e-9;
}
}

The range of a single perlin noise step is:
http://digitalfreepen.com/2017/06/20/range-perlin-noise.html
-sqrt(N/4), sqrt(N/4)
With N being the amount of dimensions. 2 in your case.
Octaves, persistence and amplitude add on top of that:
double range = 0.0;
double _amplitude = parameters.;
for (int k = 0; k < parameters.octaves; k++) {
range += sqrt(N/4) * _amplitude;
_amplitude *= parameters.persistence;
}
return range;
There might be some way to do this as a single mathematical expression. Involving pow(), but by brain fails me right now.

This is not a problem with octaves and frequency affecting amplitude, not directly at least. It is a problem with integer overflow. Because you introduce your random seed by adding it to the the x and y co-ordinates (which is unusual, I don't think this is the usual implimentation)
t += GetValue(j * freq + parameters.randomseed, i * freq + parameters.randomseed)* _amplitude;
And random seed could be huge (possibly the near full size of the int) because
this.randomseed = 2 + randomseed * randomseed;
So if you input large values for j and i you end up with the doubles that are passed through at GetValue(double x, double y) being larger than the maximum size of int, at that point when you call
int Xint = (int) x;
int Yint = (int) y;
Xint and YInt won't be anything like x and y (because x and y could be huge!) and so
double Xfrac = x - Xint;
double Yfrac = y - Yint;
could be much much larger that 1, allowing values not between -1 and 1 to be returned.
Using reasonable and small values my ranges using your code are between -1 and 1 (for amplitude 1)
As an asside, in java usually method names are methodName, not MethodName
If its useful please find annother java implimentation of perlin noise here:
http://mrl.nyu.edu/~perlin/noise/

Related

Java Perlin Noise height map generation lacks desired randomness

I am trying to generate a height map using Perlin Noise, but am having trouble with generating truly unique maps. That is, each one is a minor variation of all the others. Two examples are below:
And here is my code (most was just copied and pasted from Ken Perlin's implementation, though adapted for 2D):
public class HeightMap {
private ArrayList<Point> map = new ArrayList<>();
private double elevationMax, elevationMin;
private final int[] P = new int[512], PERMUTATION = { 151,160,137,91,90,15,
131,13,201,95,96,53,194,233,7,225,140,36,103,30,69,142,8,99,37,240,21,10,23,
190, 6,148,247,120,234,75,0,26,197,62,94,252,219,203,117,35,11,32,57,177,33,
88,237,149,56,87,174,20,125,136,171,168, 68,175,74,165,71,134,139,48,27,166,
77,146,158,231,83,111,229,122,60,211,133,230,220,105,92,41,55,46,245,40,244,
102,143,54, 65,25,63,161, 1,216,80,73,209,76,132,187,208, 89,18,169,200,196,
135,130,116,188,159,86,164,100,109,198,173,186, 3,64,52,217,226,250,124,123,
5,202,38,147,118,126,255,82,85,212,207,206,59,227,47,16,58,17,182,189,28,42,
223,183,170,213,119,248,152, 2,44,154,163, 70,221,153,101,155,167, 43,172,9,
129,22,39,253, 19,98,108,110,79,113,224,232,178,185, 112,104,218,246,97,228,
251,34,242,193,238,210,144,12,191,179,162,241, 81,51,145,235,249,14,239,107,
49,192,214, 31,181,199,106,157,184, 84,204,176,115,121,50,45,127, 4,150,254,
138,236,205,93,222,114,67,29,24,72,243,141,128,195,78,66,215,61,156,180
};
public HeightMap() {
this.map = null;
this.elevationMax = 0.0;
this.elevationMin = 0.0;
}
public HeightMap(HeightMap map) {
this.map = map.getPoints();
this.elevationMax = map.getElevationMax();
this.elevationMin = map.getElevationMin();
}
/**
* Generates a Height Map that is, along an imaginary z-axis, centered around the median elevation, given the following parameters:
* #param mapWidth the width [x] of the map
* #param mapHeight the height [y] of the map
* #param tileWidth the width [x] of each tile, or Point
* #param tileHeight the height [y] of each tile, or Point
* #param elevationMax the maximum elevation [z] of the map
* #param elevationMin the minimum elevation [z] of the map
*/
public HeightMap(int mapWidth, int mapHeight, int tileWidth, int tileHeight, double elevationMax, double elevationMin) {
this.elevationMax = elevationMax;
this.elevationMin = elevationMin;
for (int i=0; i < 256 ; i++) {
P[256+i] = P[i] = PERMUTATION[i];
}
int numTilesX = mapWidth / tileWidth;
int numTilesY = mapHeight / tileHeight;
Random r = new Random();
for (int t = 0; t < numTilesX * numTilesY; t++) {
double x = t % numTilesX;
double y = (t - x) / numTilesX;
r = new Random();
x += r.nextDouble();
y += r.nextDouble();
this.map.add(new Point(x, y, lerp(noise(x, y, 13), (elevationMin + elevationMax) / 2, elevationMax), tileWidth, tileHeight));
}
}
/**
* Ken Perlin's Improved Noise Java Implementation (https://mrl.cs.nyu.edu/~perlin/noise/)
* Adapted for 2D
* #param x the x-coordinate on the map
* #param y the y-coordinate on the map
* #param stretch the factor by which adjacent points are smoothed
* #return a value between -1.0 and 1.0 to represent the height of the terrain at (x, y)
*/
private double noise(double x, double y, double stretch) {
x /= stretch;
y /= stretch;
int X = (int)Math.floor(x) & 255, Y = (int)Math.floor(y) & 255;
x -= Math.floor(x);
y -= Math.floor(y);
double u = fade(x),
v = fade(y);
int AA = P[P[X ] + Y ],
AB = P[P[X ] + Y + 1],
BA = P[P[X + 1] + Y ],
BB = P[P[X + 1] + Y + 1];
return lerp(v, lerp(u, grad(P[AA], x, y), grad(P[BA], x - 1, y)), lerp(u, grad(P[AB], x, y - 1), grad(P[BB], x - 1, y - 1)));
}
private double fade(double t) {
return t * t * t * (t * (t * 6 - 15) + 10);
}
private double lerp(double t, double a, double b) {
return a + t * (b - a);
}
//Riven's Optimization (http://riven8192.blogspot.com/2010/08/calculate-perlinnoise-twice-as-fast.html)
private double grad(int hash, double x, double y) {
switch(hash & 0xF)
{
case 0x0:
case 0x8:
return x + y;
case 0x1:
case 0x9:
return -x + y;
case 0x2:
case 0xA:
return x - y;
case 0x3:
case 0xB:
return -x - y;
case 0x4:
case 0xC:
return y + x;
case 0x5:
case 0xD:
return -y + x;
case 0x6:
case 0xE:
return y - x;
case 0x7:
case 0xF:
return -y - x;
default: return 0; // never happens
}
}
}
Is this problem inherent in Perlin Noise because the 'height' is calculated from nearly the same (x, y) coordinate each time? Is there a way to implement the noise function so that it doesn't depend on the (x, y) coordinate of each point but still looks like terrain? Any help is greatly appreciated.
With some help from a friend of mine, I resolved the problem. Because I was using the same PERMUTATION array each generation cycle, the noise calculation was using the same base values each time. To fix this, I made a method permute() that filled PERMUTATION with the numbers 0 to 255 in a random, non-repeating order. I changed the instantiation of PERMUTATION to just be a new int[].
private final int[] P = new int[512], PERMUTATION = new int[256];
...
public void permute() {
for (int i = 0; i < PERMUTATION.length; i++) {
PERMUTATION[i] = i;
}
Random r = new Random();
int rIndex, rIndexVal;
for (int i = 0; i < PERMUTATION.length; i++) {
rIndex = r.nextInt(PERMUTATION.length);
rIndexVal = PERMUTATION[rIndex];
PERMUTATION[rIndex] = PERMUTATION[i];
PERMUTATION[i] = rIndexVal;
}
}

How to solve sine mathematic equation in java?

How to solve following mathematic equation in java?
Equation:
x + sin(x) = constant, where x is variable. I encountered this equation after 18 years. I forgot this basic concept. Please help me on this basic high school question.
I tried to code above equation x + sin(x) = constant as following, however, it is giving wrong answer. Please let me know where i am wrong.
public double balanceLength(double total_weight) {
// 5.00 assume inical value of x
return newtonRaphson( 5.00, total_weight);
}
private static double derivFunc(double x)
{
return sin(x) + x;
}
private static double func(double x, double weight)
{
return sin(x) + x - weight;
}
static double newtonRaphson(double x, double weight)
{
double h = func(x, weight) / derivFunc(x);
while (abs(h) >= EPSILON)
{
h = func(x, weight) / derivFunc(x);
x = x - h;
}
return round(x * 100.0) / 100.0 ;
}
This is a very basic implementation, only partially tested. It reruns x in radians, which satisfies y=six(x) +x for a given y :
//returned value in radians
static double evaluateSinxPlusx(double y){
double delta = y>0 ? 0.01 : -0.01 ;//change constants
double epsilon = 0.01; //to change
int iterations = 100; //accuracy
double x = 0;
double sum = 1;
while(Math.abs(y - sum) > epsilon) {
x+=delta;
//based Taylor series approximation
double term = 1.0;
sum = x;
double d = 1;
for (int i = 1; i< iterations; i++) {
term = Math.pow(x, i);
d*=i;
if (i % 4 == 1) {
sum += term/d;
}
if (i % 4 == 3) {
sum -= term/d;
}
}
}
return x;
}
//test it
public static void main(String[] args) throws Exception{
double y = 0.979;
//expected x = 0.5 radians
System.out.println("for x="+ evaluateSinxPlusx(y)+"(radians), sin(x)+x = "+ y);
y = -0.979;
//expected x = - 0.5 radians
System.out.println("for x="+ evaluateSinxPlusx(y)+"(radians), sin(x)+x = "+ y);
y = 0.33256;
//expected x = 0.16666 radians
System.out.println("for x="+ evaluateSinxPlusx(y)+"(radians), sin(x)+x = "+ y);
}
This is not a robust implementation and should be used as demo only.

Some print functions do not run in this calculation class. Why? [closed]

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 7 years ago.
Improve this question
Alongside with my main class, i want to output the table with the points of the airfoil to the command line, but right now some of the system print functions aren't working. here is my calc class:
package airfoil;
import java.text.DecimalFormat;
import java.text.NumberFormat;
public class airfoil
{
private static final int numOfCoord = 250;
double dx = 1.0 / numOfCoord;
private double m; // maximum camber in % of chord
private double p; // chordwise position of max ord., 10th of chord
private double t; // thickness in % of the cord
private String nacaNum; // NACA number - 4 digits
private double[][] coordinates; // Coordinates of the upper half
// or lower half of the airfoil
private double[][] meanLine; // mean line coordinates
public airfoil(String number) {
nacaNum = number;
m = Double.parseDouble(nacaNum.substring(0,1)) / 100.0;
p = Double.parseDouble(nacaNum.substring(1,2)) / 10.0;
t = Double.parseDouble(nacaNum.substring(2,4)) / 100.0;
meanLine = new double[2][numOfCoord]; // x values row 0, y values row 1
// x upper = row 0,
// y upper = row 1,
// x lower = row 2,
// y lower = row 3
coordinates = new double [4][numOfCoord];
System.out.println("NACA: " + nacaNum);
System.out.println("Number of coordinates: " + numOfCoord);
calcMeanLine();
calcAirfoil();
}
/*
* Calculates the values for the mean line forward of the maximum
* ordinate and aft of the maximum ordinate.
*/
private void calcMeanLine() {
double x = dx;
int j = 0;
// fwd of max ordinate
while (x <= p) {
meanLine[0][j] = x;
meanLine[1][j] = (m / (p * p))*(2*p*x - (x*x));
x += dx;
j++;
}
// aft of max ordinate
while (x <= 1.0 + dx) {
meanLine[0][j] = x;
meanLine[1][j] = (m / ((1 - p) * (1 - p))) *
((1 - 2*p) + 2*p*x - x * x);
x += dx;
j++;
}
} // end calcMeanLine
/*
* Calculate the upper and lower coordinates of the airfoil surface.
*/
private void calcAirfoil() {
double theta; // arctan(dy_dx)
double dy; // derivative of mean line equation
double yt, ml; // thickness and meanline values, respectively
double x = dx; // x-value w.r.t. chord
int j = 0; // counter for array
// calculate upper/lower surface coordinates fwd of max ordinate
while (x <= p) {
dy = (m / (p*p)) * (2*p - 2*x);
theta = Math.atan(dy);
yt = thicknessEQ(x);
ml = meanLine[1][j];
// upper surface coordinates;
coordinates[0][j] = x - yt * Math.sin(theta);
coordinates[1][j] = ml + yt * Math.cos(theta);
// lower surface coordinates
coordinates[2][j] = x + yt*Math.sin(theta);
coordinates[3][j] = ml - yt * Math.cos(theta);
x += dx;
j++;
}
// calculate the coordinates aft of max ordinate
while (x <= 1.0 + dx) {
dy = (m / ((1 - p) * (1 - p))) * ((2 * p) - (2 * x));
theta = Math.atan(dy);
yt = thicknessEQ(x);
ml = meanLine[1][j];
// upper surface coordinates;
coordinates[0][j] = x - yt * Math.sin(theta);
coordinates[1][j] = ml + yt * Math.cos(theta);
// lower surface coordinates
coordinates[2][j] = x + yt * Math.sin(theta);
coordinates[3][j] = ml - yt * Math.cos(theta);
x += dx;
j++;
}
System.out.println("j = " + j);
} // end calcAirfoil
/*
* Thickness equation
*/
private double thicknessEQ(double x) {
return ((t / 0.2) * (0.2969 * Math.sqrt(x) - (0.126 * x) -
(0.3526 * x * x) + (0.28430 * x * x * x) -
(0.1015 * x * x * x * x)));
}
public String toString() {
String str = "";
NumberFormat df = new DecimalFormat("0.0000");
System.out.println("Xu\tYu\tXl\tYl");
for (int j = 0; j < numOfCoord; j++) {
str += df.format(coordinates[0][j]) + "\t" +
df.format(coordinates[1][j]) + "\t" +
df.format(coordinates[2][j]) + "\t" +
df.format(coordinates[3][j]) + "\n";
}
return str;
}
/*
* Return the coordinates array
*/
public double[][] getCoordinates() { return coordinates; }
public int getSize() { return numOfCoord; }
} // end Airfoil class
This part of the class is supposed to print a table, but it isnt doing anything:
public String toString() {
String str = "";
NumberFormat df = new DecimalFormat("0.0000");
System.out.println("Xu\tYu\tXl\tYl");
for (int j = 0; j < numOfCoord; j++) {
str += df.format(coordinates[0][j]) + "\t" +
df.format(coordinates[1][j]) + "\t" +
df.format(coordinates[2][j]) + "\t" +
df.format(coordinates[3][j]) + "\n";
}
return str;
}
So what can I do to make these things print correctly?
Your System.out.println("Xu\tYu\tXl\tYl"); code prints the following: Xu Yu Xl Yl because you did not add any variables to it. You could change it to:
public String toString() {
String str = "";
NumberFormat df = new DecimalFormat("0.0000");
for (int j = 0; j < numOfCoord; j++) {
str += df.format(coordinates[0][j]) + "\t" +
df.format(coordinates[1][j]) + "\t" +
df.format(coordinates[2][j]) + "\t" +
df.format(coordinates[3][j]) + "\n";
}
System.out.println(str);
return str;
}
Anyway, don't print in toString() function. toString() shouldn't print anything, it should just return the String so that you can print it or do whatever you want with it.
Airfoil airfoil = new Airfoil(); // Yes, first letter uppercase recommended
// do stuff
System.out.println(airfoil.toString());
EDIT: It works for me (I think). I used the input 1000 (by the way, you should use try/catch for numbers with 3 characters or less or it will crash), and this is the output I got (only the beginning and ending), as it's long.
NACA: 1000
Number of coordinates: 250
j = 250
0.0040 0.0100 0.0040 0.0100
0.0080 0.0100 0.0080 0.0100
0.0120 0.0100 0.0120 0.0100
[...]
0.9920 0.0002 0.9920 0.0002
0.9960 0.0001 0.9960 0.0001
1.0000 -0.0000 1.0000 -0.0000
This is the toString() code used to make it work:
public String toString() {
String str = "";
NumberFormat df = new DecimalFormat("0.0000");
// System.out.println("Xu\tYu\tXl\tYl");
for (int j = 0; j < numOfCoord; j++) {
str += df.format(coordinates[0][j]) + "\t" +
df.format(coordinates[1][j]) + "\t" +
df.format(coordinates[2][j]) + "\t" +
df.format(coordinates[3][j]) + "\n";
}
return str;
}
And the main I used:
public static void main (String args[]){
Airfoil air = new Airfoil("1000");
System.out.println(air.toString());
}

Trying to calculate sunrise...ain't getting the right answer

This is my current code:
public class Sunpos {
final private double Pi = Math.PI;
final private double eul = 2.71828182845904523552 ;
final private double sonauf = 90;
final private double RAD = 0.017453292519943295769236907684886;
public double sunrisefinal (double Breitengrad, double Laengengrad, int tagzahl, int sommerzeit, int nacht) {
double lngHour = Laengengrad/15;
double t = tagzahl + ((6 - lngHour)/24);
// double ab = tagzahl + ((18 - lngHour)/24);
double M = (0.9856 * t) - 3.289;
double L = M + (1.916 * Math.sin(M)) + (0.020 * Math.sin(2 * M)) + 282.634;
if (L >= 359) { L -= 360; }
else if (L < 0) { L += 360; }
double RA = (Math.atan(0.91764 * Math.tan(Pi/180)*L));
if (RA >= 359) { RA -= 360; }
else if (RA < 0) { RA += 360; }
double Lquadrant = (Math.floor(L/90)*90);
double RAquadrant = (Math.floor(RA/90))*90;
RA = RA + (Lquadrant - RAquadrant);
RA = RA/15;
double sinDec = 0.39782 * Math.sin((Pi/180)*L);
double cosDec = (180/Pi)*(Math.cos(Math.asin(sinDec)));
double cosH = (Math.cos((Pi/180)*sonauf)-(sinDec*Math.sin((Pi/180)*Breitengrad)))/(cosDec * Math.cos((Pi/180)*Breitengrad));
double H = 360 - Math.acos(cosH);
H /= 15;
double T = H + RA -(0.06571 * t) - 6.622;
double UTC = T - lngHour;
if (UTC >= 23) { UTC -= 24; }
else if (UTC < 0) { UTC += 24; }
double locTime = UTC; // Fuer die schweiz!
System.out.println(locTime);
return(0);
}
The inputs are the following: ( 50, 10, 294, 1, 0). The last 2 can be ignored.
Now I am basing this on the following page:
http://williams.best.vwh.net/sunrise_sunset_algorithm.htm
The code should be complete according to the site, but I don't get anywhere near the supposed results. I should get around 7.5 for today but I'm getting a 9.358.
Now, that might be because something with radiants/degrees? I can't quite get my Mind into that, as I've been trying to insert those converters (Pi/180) into the code, without any usable result.
Can anyone tell me where to put them or point me in the right direction? I've spent waaaay too much time on this already, and now I'm so close.
I'll just post my implementation here in case people need it (ported from the same source as yours)
https://gist.github.com/zhong-j-yu/2232343b14a5b5ef5b9d
public class SunRiseSetAlgo
{
static double calcSunrise(int dayOfYear, double localOffset, double latitude, double longitude)
{
return calc(dayOfYear, localOffset, latitude, longitude, true);
}
static double calcSunset(int dayOfYear, double localOffset, double latitude, double longitude)
{
return calc(dayOfYear, localOffset, latitude, longitude, false);
}
// http://williams.best.vwh.net/sunrise_sunset_algorithm.htm
static double calc(int dayOfYear, double localOffset, double latitude, double longitude, boolean rise)
{
//1. first calculate the day of the year
// int N1 = floor(275 * month / 9.0);
// int N2 = floor((month + 9) / 12.0);
// int N3 = (1 + floor((year - 4 * floor(year / 4.0) + 2) / 3.0));
// int N = N1 - (N2 * N3) + day - 30;
int N = dayOfYear;
//2. convert the longitude to hour value and calculate an approximate time
double lngHour = longitude / 15;
double t = rise?
N + (( 6 - lngHour) / 24) :
N + ((18 - lngHour) / 24);
//3. calculate the Sun's mean anomaly
double M = (0.9856 * t) - 3.289;
//4. calculate the Sun's true longitude
double L = M + (1.916 * sin(M)) + (0.020 * sin(2 * M)) + 282.634;
L = mod(L, 360);
//5a. calculate the Sun's right ascension
double RA = atan(0.91764 * tan(L));
RA = mod(RA, 360);
//5b. right ascension value needs to be in the same quadrant as L
double Lquadrant = (floor( L/90)) * 90;
double RAquadrant = (floor(RA/90)) * 90;
RA = RA + (Lquadrant - RAquadrant);
//5c. right ascension value needs to be converted into hours
RA = RA / 15;
//6. calculate the Sun's declination
double sinDec = 0.39782 * sin(L);
double cosDec = cos(asin(sinDec));
//7a. calculate the Sun's local hour angle
double zenith = 90 + 50.0/60;
double cosH = (cos(zenith) - (sinDec * sin(latitude))) / (cosDec * cos(latitude));
if (cosH > 1)
throw new Error("the sun never rises on this location (on the specified date");
if (cosH < -1)
throw new Error("the sun never sets on this location (on the specified date");
//7b. finish calculating H and convert into hours
double H = rise?
360 - acos(cosH) :
acos(cosH);
H = H / 15;
//8. calculate local mean time of rising/setting
double T = H + RA - (0.06571 * t) - 6.622;
//9. adjust back to UTC
double UT = T - lngHour;
//10. convert UT value to local time zone of latitude/longitude
double localT = UT + localOffset;
localT = mod(localT, 24);
return localT;
}
static int floor(double d){ return (int)Math.floor(d); }
static double sin(double degree)
{
return Math.sin(degree*Math.PI/180);
}
static double cos(double degree)
{
return Math.cos(degree*Math.PI/180);
}
static double tan(double degree)
{
return Math.tan(degree*Math.PI/180);
}
static double atan(double x)
{
return Math.atan(x) *180/Math.PI;
}
static double asin(double x)
{
return Math.asin(x) *180/Math.PI;
}
static double acos(double x)
{
return Math.acos(x) *180/Math.PI;
}
static double mod(double x, double lim)
{
return x - lim * floor(x/lim);
}
}
Everone seems to link to this http://williams.best.vwh.net/sunrise_sunset_algorithm.htm
which doesn't exist anymore. Why not try something that gets updated once in a while like https://en.wikipedia.org/wiki/Sunrise_equation
Then if you like you could help edit it to make it better.

basic math equation math to java code

so i have a math equation that i need to use in java but for some reason my code is giving me small errors :(
the math equation is describe on this web page in the section extra credit
my current code outpouts 4000 and the answere is 4005 what am i duing wrong ?
my test class lookes like this
public class MainActivity {
public static void main(String[] args) throws Exception{
double baseMaterial =556;
int me =5;
int ml = 10;
int extraMaterial = 3444;
System.out.println(""+calculateMiniralTotal(baseMaterial,me,ml,extraMaterial));
}
public static double calculateMiniralTotal(double perfekt,int me,int ml,int extraMaterial) {
double s = (perfekt + (perfekt * (10 / (ml + 1)) / 100));
s = Math.round(s);
double r = s + (perfekt * (0.25 - (0.05 * me)));
r = Math.round(r);
double q = extraMaterial + (extraMaterial * (0.25 - (0.05 * me)));
q = Math.round(q);
//double r=q;
r = r + q;
return Math.round(r);
}
}
You are performing integer division with (10 / (ml + 1)) / 100, which in Java must result in another int. Your ml is 10, and in Java, 10 / 11 is 0, not 0.909..., and nothing is added to s.
Use a double literal or cast to double to force floating-point computations.
double s = (perfekt + (perfekt * (10.0 / (ml + 1)) / 100));
or
double s = (perfekt + (perfekt * ( (double) 10 / (ml + 1)) / 100));
Making either change makes the output:
4005.0
When you multiply a double by an int you get an int back.
public class Main
{
public static void main(String[] args)
throws Exception
{
double baseMaterial = 556;
int me = 5;
int ml = 10;
int extraMaterial = 3444;
System.out.println("" + calculateMiniralTotal(baseMaterial, me, ml, extraMaterial));
}
public static double calculateMiniralTotal(double perfekt, int me, int ml, int extraMaterial)
{
double s = (perfekt + (perfekt * (10.0 / (ml + 1)) / 100.0)); // <-- changed from 10 to 10.0 and 100 to 100.0. This way they are doubles too
s = Math.round(s);
double r = s + (perfekt * (0.25 - (0.05 * me)));
r = Math.round(r);
double q = extraMaterial + (extraMaterial * (0.25 - (0.05 * me)));
q = Math.round(q);
// double r=q;
r = r + q;
return Math.round(r);
}
}

Categories

Resources