Exponential integral and gamma function [closed] - java

Closed. This question does not meet Stack Overflow guidelines. It is not currently accepting answers.
We don’t allow questions seeking recommendations for books, tools, software libraries, and more. You can edit the question so it can be answered with facts and citations.
Closed 7 years ago.
Improve this question
In order to solve this problem, without iteration:
Recursion: Sum of series of n terms
calculating for a given n: 1 + 2*3 + 3*4*5 + 4*5*6*7 + ... +
n*(n+1)...(2n-1)
with this mathematical answer:
https://math.stackexchange.com/questions/1590673/formula-to-calculate-directly-1-23-345-4567-nn1-2n#1590687
It here a library in java to get Exponential integral and Gamma function ?
as in this formula:
Thanks

Apache Commons Math library has Gamma class.
I have adapted code from Exponential Integrals page from C to Java for Ei(x):
/**
*
*/
package wilx.math.exponential.integrals;
/**
* #author wilx
*/
public class ExponentialIntegrals
{
// Internally Defined Constants //
static final double DBL_EPSILON = Math.ulp(1.0);
static final double epsilon = 10.0 * DBL_EPSILON;
static final double DBL_MAX = Double.MAX_VALUE;
// //////////////////////////////////////////////////////////////////////////////
// double xExponential_Integral_Ei( double x ) //
// //
// Description: //
// The exponential integral Ei(x) is the integral with integrand //
// exp(t) / t //
// where the integral extends from -inf to x. //
// Note that there is a singularity at t = 0. Therefore for x > 0, the //
// integral is defined to be the Cauchy principal value: //
// lim { I[-inf, -eta] exp(-t) dt / t + I[eta, x] exp(-t) dt / t } //
// in which the limit is taken as eta > 0 approaches 0 and I[a,b] //
// denotes the integral from a to b. //
// //
// Arguments: //
// double x The argument of the exponential integral Ei(). //
// //
// Return Value: //
// The value of the exponential integral Ei evaluated at x. //
// If x = 0.0, then Ei is -inf and -DBL_MAX is returned. //
// //
// Example: //
// double y, x; //
// //
// ( code to initialize x ) //
// //
// y = xExponential_Integral_Ei( x ); //
// //////////////////////////////////////////////////////////////////////////////
public static double Exponential_Integral_Ei(final double x)
{
if (x < -5.0)
{
return Continued_Fraction_Ei(x);
}
if (x == 0.0)
{
return -DBL_MAX;
}
if (x < 6.8)
{
return Power_Series_Ei(x);
}
if (x < 50.0)
{
return Argument_Addition_Series_Ei(x);
}
return Continued_Fraction_Ei(x);
}
// //////////////////////////////////////////////////////////////////////////////
// static double Continued_Fraction_Ei( double x ) //
// //
// Description: //
// For x < -5 or x > 50, the continued fraction representation of Ei //
// converges fairly rapidly. //
// //
// The continued fraction expansion of Ei(x) is: //
// Ei(x) = -exp(x) { 1/(-x+1-) 1/(-x+3-) 4/(-x+5-) 9/(-x+7-) ... }. //
// //
// //
// Arguments: //
// double x //
// The argument of the exponential integral Ei(). //
// //
// Return Value: //
// The value of the exponential integral Ei evaluated at x. //
// //////////////////////////////////////////////////////////////////////////////
private static double Continued_Fraction_Ei(final double x)
{
double Am1 = 1.0;
double A0 = 0.0;
double Bm1 = 0.0;
double B0 = 1.0;
double a = expl(x);
double b = -x + 1.0;
double Ap1 = b * A0 + a * Am1;
double Bp1 = b * B0 + a * Bm1;
int j = 1;
a = 1.0;
while (fabsl(Ap1 * B0 - A0 * Bp1) > epsilon * fabsl(A0 * Bp1))
{
if (fabsl(Bp1) > 1.0)
{
Am1 = A0 / Bp1;
A0 = Ap1 / Bp1;
Bm1 = B0 / Bp1;
B0 = 1.0;
}
else
{
Am1 = A0;
A0 = Ap1;
Bm1 = B0;
B0 = Bp1;
}
a = -j * j;
b += 2.0;
Ap1 = b * A0 + a * Am1;
Bp1 = b * B0 + a * Bm1;
j += 1;
}
return (-Ap1 / Bp1);
}
// //////////////////////////////////////////////////////////////////////////////
// static double Power_Series_Ei( double x ) //
// //
// Description: //
// For -5 < x < 6.8, the power series representation for //
// (Ei(x) - gamma - ln|x|)/exp(x) is used, where gamma is Euler's gamma //
// constant. //
// Note that for x = 0.0, Ei is -inf. In which case -DBL_MAX is //
// returned. //
// //
// The power series expansion of (Ei(x) - gamma - ln|x|) / exp(x) is //
// - Sum(1 + 1/2 + ... + 1/j) (-x)^j / j!, where the Sum extends //
// from j = 1 to inf. //
// //
// Arguments: //
// double x //
// The argument of the exponential integral Ei(). //
// //
// Return Value: //
// The value of the exponential integral Ei evaluated at x. //
// //////////////////////////////////////////////////////////////////////////////
private static double Power_Series_Ei(final double x)
{
double xn = -x;
double Sn = -x;
double Sm1 = 0.0;
double hsum = 1.0;
final double g = 0.5772156649015328606065121;
double y = 1.0;
double factorial = 1.0;
if (x == 0.0)
{
return -DBL_MAX;
}
while (fabsl(Sn - Sm1) > epsilon * fabsl(Sm1))
{
Sm1 = Sn;
y += 1.0;
xn *= (-x);
factorial *= y;
hsum += (1.0 / y);
Sn += hsum * xn / factorial;
}
return (g + logl(fabsl(x)) - expl(x) * Sn);
}
static final double ei[] = { 1.915047433355013959531e2,
4.403798995348382689974e2, 1.037878290717089587658e3,
2.492228976241877759138e3, 6.071406374098611507965e3,
1.495953266639752885229e4, 3.719768849068903560439e4,
9.319251363396537129882e4, 2.349558524907683035782e5,
5.955609986708370018502e5, 1.516637894042516884433e6,
3.877904330597443502996e6, 9.950907251046844760026e6,
2.561565266405658882048e7, 6.612718635548492136250e7,
1.711446713003636684975e8, 4.439663698302712208698e8,
1.154115391849182948287e9, 3.005950906525548689841e9,
7.842940991898186370453e9, 2.049649711988081236484e10,
5.364511859231469415605e10, 1.405991957584069047340e11,
3.689732094072741970640e11, 9.694555759683939661662e11,
2.550043566357786926147e12, 6.714640184076497558707e12,
1.769803724411626854310e13, 4.669055014466159544500e13,
1.232852079912097685431e14, 3.257988998672263996790e14,
8.616388199965786544948e14, 2.280446200301902595341e15,
6.039718263611241578359e15, 1.600664914324504111070e16,
4.244796092136850759368e16, 1.126348290166966760275e17,
2.990444718632336675058e17, 7.943916035704453771510e17,
2.111342388647824195000e18, 5.614329680810343111535e18,
1.493630213112993142255e19, 3.975442747903744836007e19,
1.058563689713169096306e20 };
private static double expl(final double x)
{
return Math.exp(x);
}
private static double fabsl(final double x)
{
return Math.abs(x);
}
private static double logl(final double x)
{
return Math.log(x);
}
// //////////////////////////////////////////////////////////////////////////////
// static double Argument_Addition_Series_Ei(double x) //
// //
// Description: //
// For 6.8 < x < 50.0, the argument addition series is used to calculate //
// Ei. //
// //
// The argument addition series for Ei(x) is: //
// Ei(x+dx) = Ei(x) + exp(x) Sum j! [exp(j) expj(-dx) - 1] / x^(j+1), //
// where the Sum extends from j = 0 to inf, |x| > |dx| and expj(y) is //
// the exponential polynomial expj(y) = Sum y^k / k!, the Sum extending //
// from k = 0 to k = j. //
// //
// Arguments: //
// double x //
// The argument of the exponential integral Ei(). //
// //
// Return Value: //
// The value of the exponential integral Ei evaluated at x. //
// //////////////////////////////////////////////////////////////////////////////
private static double Argument_Addition_Series_Ei(final double x)
{
final int k = (int) (x + 0.5);
int j = 0;
final double xx = k;
final double dx = x - xx;
double xxj = xx;
final double edx = expl(dx);
double Sm = 1.0;
double Sn = (edx - 1.0) / xxj;
double term = DBL_MAX;
double factorial = 1.0;
double dxj = 1.0;
while (fabsl(term) > epsilon * fabsl(Sn))
{
j++;
factorial *= j;
xxj *= xx;
dxj *= (-dx);
Sm += (dxj / factorial);
term = (factorial * (edx * Sm - 1.0)) / xxj;
Sn += term;
}
return ei[k - 7] + Sn * expl(xx);
}
}

Related

How to solve Newton's Cooling Law using Runge-Kutta method (RK4) [closed]

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 3 years ago.
Improve this question
I need help implementing my working 4th-Order Runge-Kutta method for solving Newton's Cooling Law. Since time (t) is introduced with this problem, I am confused on the placings for the given conditions. Here is what's given: time interval begins t = 0 to t = 20 (in seconds), object temp = 300, ambient temp = 70, time increment is .1, and constant of proportionality = 0.19
public class RungeKutta {
public static double NewtonsCoolingLaw(double objectTemp,double ambientTemp)
{
double k = 0.19;
return -k * (objectTemp - ambientTemp);
}
public static void main(String[] args) {
double result = 0.0;
double initialObjectTemp = 300.0, givenAmbientTemp = 70.0;
double deltaX = (20.0 - 0)/10000;
for(double t = 0.0; t <= 20.0; t += .1)
{
double k1 = deltaX * NewtonsLaw(initialObjectTemp,givenAmbientTemp);
double k2 = deltaX * NewtonsLaw(initialObjectTemp + (deltaX/2.0),givenAmbientTemp + (k1/2.0));
double k3 = deltaX * NewtonsLaw(initialObjectTemp + (deltaX/2.0), givenAmbientTemp + (k2/2.0));
double k4 = deltaX * NewtonsLaw(initialObjectTemp + deltaX, givenAmbientTemp + k3);
givenAmbientTemp = givenAmbientTemp + (1.0/6.0) * (k1 + (2.0 * k2) + (2.0 * k3) + k4);
result = givenAmbientTemp;
}
System.out.println("The approx. object temp after 20 seconds is: " + result);
}
}
Bellow is my RK4 method for solving ODEs. In the code below, I solve the ODE y' = y - x to approximate y(1.005) given that y(1) = 10 and delta x = 0.001
public class RungeKutta {
public static double functionXnYn(double x,double y)
{
return y-x;
}
public static void main(String[] args) {
double deltaX = (1.005 - 0)/10000;
double y = 10.0;
double result = 0.0;
for(double x = 1.0; x <= 1.005; x = x + deltaX)
{
double k1 = deltaX * functionXnYn(x,y);
double k2 = deltaX * functionXnYn(x + (deltaX/2.0),y + (k1/2.0));
double k3 = deltaX * functionXnYn(x + (deltaX/2.0), y + (k2/2.0));
double k4 = deltaX * functionXnYn(x + deltaX, y + k3);
y = y + (1.0/6.0) * (k1 + (2.0 * k2) + (2.0 * k3) + k4);
result = y;
}
System.out.println("The value of y(1.005) is: " + result);
}
}
Based on the formula T(t) = Ts + (T0 - Ts) * e^(-k*t) I should have an approximation of 75.1 for solving Newton's DE. Ts = ambient temp, T0 = object initial temp, t = 20 (seconds elapsed), and k = .19 constant of proportionality
I'm guessing (but not really hard) that the ODE you are trying to solve is
dT(t)/dt = -k*(T(t)-T_amb)
As you can see, the right side does not directly depend on the time.
As you make no attempts to code for a system, it is likely that the ambient temperature T_amb is a constant. Thus moving the constants around and using consistent function names and returning the ODE function arguments to the format time, state variable
public class RungeKutta {
public static double CoolingLaw(double time, double objectTemp)
{
double k = 0.19, ambientTemp = 70.0;
return -k * (objectTemp - ambientTemp);
}
public static void main(String[] args) {
double result = 0.0;
double objectTemp = 300.0;
double dt = 0.1
for(double t = 0.0; t <= 20.0; t += dt)
{
double k1 = dt * CoolingLaw(t, objectTemp);
double k2 = dt * CoolingLaw(t + (dt/2.0), objectTemp + (k1/2.0));
double k3 = dt * CoolingLaw(t + (dt/2.0), objectTemp + (k2/2.0));
double k4 = dt * CoolingLaw(t + dt, objectTemp + k3);
objectTemp = objectTemp + (1.0/6.0) * (k1 + (2.0 * k2) + (2.0 * k3) + k4);
result = objectTemp;
}
System.out.println("The approx. object temp after 20 seconds is: " + result);
}
}

Make Perlin noise with sharp edges

Hi so i am using the algorithm i found to generate perlin noise. What i want to do is create sharper edges with less curves Picture .
private static final double F2 = 0.5*(Math.sqrt(3.0)-1.0);
public float[][] generateSimplexNoise(int w, int h, double fre){
float [][]n = new float[w][h];
double f = fre /(float)w;
for(int i = 0; i < w ; i++){
for(int j = 0; j < h ; j++){
n[i][j] = (float) noise(i*f,j*f);
n[i][j] = (n[i][j]+1)/2; //CONVERTS TO 0-1 SCALE
}
}
return n;
}
// 2D simplex noise
public double noise(double xin, double yin) {
double n0, n1, n2; // Noise contributions from the three corners
// Skew the input space to determine which simplex cell we're in
double s = (xin+yin)*F2; // Hairy factor for 2D
int i = fastfloor(xin+s);
int j = fastfloor(yin+s);
double t = (i+j)*G2;
double X0 = i-t; // Unskew the cell origin back to (x,y) space
double Y0 = j-t;
double x0 = xin-X0; // The x,y distances from the cell origin
double y0 = yin-Y0;
// For the 2D case, the simplex shape is an equilateral triangle.
// Determine which simplex we are in.
int i1, j1; // Offsets for second (middle) corner of simplex in (i,j) coords
if(x0>y0) {i1=1; j1=0;} // lower triangle, XY order: (0,0)->(1,0)->(1,1)
else {i1=0; j1=1;} // upper triangle, YX order: (0,0)->(0,1)->(1,1)
// A step of (1,0) in (i,j) means a step of (1-c,-c) in (x,y), and
// a step of (0,1) in (i,j) means a step of (-c,1-c) in (x,y), where
// c = (3-sqrt(3))/6
double x1 = x0 - i1 + G2; // Offsets for middle corner in (x,y) unskewed coords
double y1 = y0 - j1 + G2;
double x2 = x0 - 1.0 + 2.0 * G2; // Offsets for last corner in (x,y) unskewed coords
double y2 = y0 - 1.0 + 2.0 * G2;
// Work out the hashed gradient indices of the three simplex corners
int ii = i & 255;
int jj = j & 255;
int gi0 = permMod12[ii+perm[jj]];
int gi1 = permMod12[ii+i1+perm[jj+j1]];
int gi2 = permMod12[ii+1+perm[jj+1]];
// Calculate the contribution from the three corners
double t0 = 0.5 - x0*x0-y0*y0;
if(t0<0) n0 = 0.0;
else {
t0 *= t0;
n0 = t0 * t0 * dot(grad3[gi0], x0, y0); // (x,y) of grad3 used for 2D gradient
}
double t1 = 0.5 - x1*x1-y1*y1;
if(t1<0) n1 = 0.0;
else {
t1 *= t1;
n1 = t1 * t1 * dot(grad3[gi1], x1, y1);
}
double t2 = 0.5 - x2*x2-y2*y2;
if(t2<0) n2 = 0.0;
else {
t2 *= t2;
n2 = t2 * t2 * dot(grad3[gi2], x2, y2);
}
// Add contributions from each corner to get the final noise value.
// The result is scaled to return values in the interval [-1,1].
return 65.0 * (n0 + n1 + n2);
}
Having a noise lower than .25 classifies the block as brick and anything above .25 as grass.
Above is what i use to create the noise and convert it to a 0-1 scale. Any ideas/help with making the noise less curvy?
Looking at the image you linked to in the question the easiest solution is to sample at lower resolution and use a threshold filter to create the contrast you need.
double squareness = 50.0; // size of blocks values > 1 and in pixels
double threshold = 4; // number of levels
double pixVal;
// then inside the sampling loop
for(int i = 0; i < w ; i++){
for(int j = 0; j < h ; j++){
pixVal = noise(Math.floor(i / squareness) * squareness * f,
Math.floor(j / squareness) * squareness * f);
pixVal = pixVal / 2.0 + 0.5; // normalize
pixVal = Math.floor(pixVal * threshold) / thresholds;
n[i][j] = (float) pixVal; // put in array
}
}
You may wish to use a second noise function that you use to modify the squareness to reduce the regularity of boundaries
double sqrMin = 50.0; // min
double sqrMax = 150.0; // max
double thresholdSq = 4;
double threshold = 4;
double pixVal;
double square;
double scale = 1.0/3.0;
// then inside the sampling loop
for(int i = 0; i < w ; i++){
for(int j = 0; j < h ; j++){
square = noise(i * f * scale, i * j * scale) / 2.0 + 0.5;
square = Math.floor(square * thresholdSq) / thresholdSq;
square = square * (sqrMax - sqrMin) + sqrMin;
pixVal = noise(Math.floor(i / square ) * square * f,
Math.floor(j / square ) * square * f);
pixVal = pixVal / 2.0 + 0.5; // normalize
pixVal = Math.floor(pixVal * threshold) / thresholds;
n[i][j] = (float) pixVal; // put in array
}
}
If it looks good I do not know, its just a variation I thought of while adding the answer.

Java Convert double to int

I have this code, and the input in the textfield is 50, so its output should be 25,
but there is a error, because no output
button_1.addActionListener(new ActionListener() {
String tfg = textField.getText().toString();
String tfc = textField.getText();
public void actionPerformed(ActionEvent e) {
if(textField.getText().toString().equals("0") ||
textField.getText().toString().equals("") ||
textField.getText().toString().equals(" ") ||
textField.getText().toString().matches("[a-zA-Z]+")) {
JOptionPane.showMessageDialog(Cow.this,
"Tree Amount Should Be 1 or More",
"Invalid Tree Amount",
JOptionPane.ERROR_MESSAGE);
}
if(!tfg.equals("0")) {
try {
int tfgg = Integer.parseInt(tfc);
int trcs = tfgg * 1;
double trcp = 1 / 2;
int trcc = (int) trcp * trcs;
System.out.println(new Integer(trcc).toString());
} catch (NumberFormatException se) {
}
}
}
});
I try to convert from my php to that code, here is my php code :
$doorSeed = $mount * 1;
$doorPrice = 1 / 2;
$doorConvert = $doorPrice * $doorSeed;
echo "Treasure Chest Seed = ".$doorSeed." Price : ".$doorConvert." World Lock <br>";
int trcc = (int) trcp * trcs;
Try this instead
int trcc = (int) (trcp * trcs);
You need to cast the complete expression [(trcp * trcs)] instead of just the first variable trcp to int. The other variable in the expression trcs is of double type, so the result of the expression become double. That is why you cast the complete expression. So your end result will be int
int tfgg = Integer.parseInt(tfc.trim()); // tfc = 4; tfgg = 4;
int trcs = tfgg * 1; // trcs = 4 * 1 = 5;
double trcp = 1.0 / 2; // trcp = 0.5;
int trcc = (int) (trcp * trcs); // trcc = (0.5 * 5) = (2.5) = 2;
System.out.println(trcc); // 2;
double trcp = 1.0 / 2;
Here make at least one value as double so the expression will be evaluated as double as suggested by #tunaki.
Also you don't need this statement in your code int trcs = tfgg * 1;.
Use like this:
String tfg ;
String tfc ;
public void actionPerformed(ActionEvent e) {
tfg = textField.getText();
tfc = textField.getText();
if(textField.getText().equals("0") || textField.getText().equals("") || textField.getText().equals(" ") || textField.getText().matches("[a-zA-Z]+")) {
JOptionPane.showMessageDialog(Cow.this,
"Tree Amount Should Be 1 or More",
"Invalid Tree Amount",
JOptionPane.ERROR_MESSAGE);
}
if(!tfg.equals("0")) {
try {
int tfgg = Integer.parseInt(tfc.trim()); // tfc = 4;
int trcs = tfgg; // trcs = 4 * 1 = 5
double trcp = 1.0 / 2; // trcp = 0.5
int trcc = (int) (trcp * trcs); // trcc = (0.5 * 5) = (2.5) = 2
System.out.println("HI: "+trcc);
} catch (NumberFormatException ignored) {
}
Your problem is at this line:
double trcp = 1 / 2;
This does not result in trcp = 0.5 but trcp = 0.0, because you are dividing integer values (and so are using integer division).
You should use the following code:
double trcp = 1.0 / 2;
to force division using doubles.
Other comments:
new Integer(trcc).toString() should be replaced with String.valueOf(trcc).
Avoid using empty catch statements: at minimum, log the exception
What's the point of this line: int trcs = tfgg * 1;?
Basically you have this (int)0.5 = 0.
In your case, trcp = 0.5 and is double, so when it's cast to integer the result is 0.
And when you do (int)a + b, the true operation with parenthesis for priority here is: ((int)a)+(b), so what you have to is the following:
int trcc = (int) (trcp * trcs);
instead of the following:
int trcc = (int) trcp * trcs;

Mahout: adjusted cosine similarity for item based recommender

For an assignment I'm supposed to test different types of recommenders, which I have to implement first. I've been looking around for a good library to do that (I had thought about Weka at first) and stumbled upon Mahout.
I must therefore put forward that: a) I'm completely new to Mahout b) I do not have a strong background in recommenders nor their algorithms (otherwise I wouldn't be doing this class...) and c) sorry but I'm far from being the best developper in the world ==> I'd appreciate if you could use layman terms (as far as possible...) :)
I've been following some tutorials (e.g. this, as well as part2) and got some preliminary results on item-based and user-based recommenders.
However, I'm not very happy with the item-based prediction. So far, I've only found similarity functions that do not take into consideration the users' rating-biases. I was wondering if there is something like adjusted cosine similarity. Any hints?
Here is a sample of the AdjustedCosineSimilarity I created. You must remember that this will be slower than PearsonCorrelationSimilarity because of the sqrt computations, but will produce better results. At least for my dataset results were much better. But you should make a trade off, quality/performance, and depending of your needs you should use the implementation you want.
/**
* Custom implementation of {#link AdjustedCosineSimilarity}
*
* #author dmilchevski
*
*/
public class AdjustedCosineSimilarity extends AbstractSimilarity {
/**
* Creates new {#link AdjustedCosineSimilarity}
*
* #param dataModel
* #throws TasteException
*/
public AdjustedCosineSimilarity(DataModel dataModel)
throws TasteException {
this(dataModel, Weighting.UNWEIGHTED);
}
/**
* Creates new {#link AdjustedCosineSimilarity}
*
* #param dataModel
* #param weighting
* #throws TasteException
*/
public AdjustedCosineSimilarity(DataModel dataModel, Weighting weighting)
throws TasteException {
super(dataModel, weighting, true);
Preconditions.checkArgument(dataModel.hasPreferenceValues(),
"DataModel doesn't have preference values");
}
/**
* Compute the result
*/
#Override
double computeResult(int n, double sumXY, double sumX2, double sumY2, double sumXYdiff2) {
if (n == 0) {
return Double.NaN;
}
// Note that sum of X and sum of Y don't appear here since they are
// assumed to be 0;
// the data is assumed to be centered.
double denominator = Math.sqrt(sumX2) * Math.sqrt(sumY2);
if (denominator == 0.0) {
// One or both parties has -all- the same ratings;
// can't really say much similarity under this measure
return Double.NaN;
}
return sumXY / denominator;
}
/**
* Gets the average preference
* #param prefs
* #return
*/
private double averagePreference(PreferenceArray prefs){
double sum = 0.0;
int n = prefs.length();
for(int i=0; i<n; i++){
sum+=prefs.getValue(i);
}
if(n>0){
return sum/n;
}
return 0.0d;
}
/**
* Compute the item similarity between two items
*/
#Override
public double itemSimilarity(long itemID1, long itemID2) throws TasteException {
DataModel dataModel = getDataModel();
PreferenceArray xPrefs = dataModel.getPreferencesForItem(itemID1);
PreferenceArray yPrefs = dataModel.getPreferencesForItem(itemID2);
int xLength = xPrefs.length();
int yLength = yPrefs.length();
if (xLength == 0 || yLength == 0) {
return Double.NaN;
}
long xIndex = xPrefs.getUserID(0);
long yIndex = yPrefs.getUserID(0);
int xPrefIndex = 0;
int yPrefIndex = 0;
double sumX = 0.0;
double sumX2 = 0.0;
double sumY = 0.0;
double sumY2 = 0.0;
double sumXY = 0.0;
double sumXYdiff2 = 0.0;
int count = 0;
// No, pref inferrers and transforms don't appy here. I think.
while (true) {
int compare = xIndex < yIndex ? -1 : xIndex > yIndex ? 1 : 0;
if (compare == 0) {
// Both users expressed a preference for the item
double x = xPrefs.getValue(xPrefIndex);
double y = yPrefs.getValue(yPrefIndex);
long xUserId = xPrefs.getUserID(xPrefIndex);
long yUserId = yPrefs.getUserID(yPrefIndex);
double xMean = averagePreference(dataModel.getPreferencesFromUser(xUserId));
double yMean = averagePreference(dataModel.getPreferencesFromUser(yUserId));
sumXY += (x - xMean) * (y - yMean);
sumX += x;
sumX2 += (x - xMean) * (x - xMean);
sumY += y;
sumY2 += (y - yMean) * (y - yMean);
double diff = x - y;
sumXYdiff2 += diff * diff;
count++;
}
if (compare <= 0) {
if (++xPrefIndex == xLength) {
break;
}
xIndex = xPrefs.getUserID(xPrefIndex);
}
if (compare >= 0) {
if (++yPrefIndex == yLength) {
break;
}
yIndex = yPrefs.getUserID(yPrefIndex);
}
}
double result;
// See comments above on these computations
double n = (double) count;
double meanX = sumX / n;
double meanY = sumY / n;
// double centeredSumXY = sumXY - meanY * sumX - meanX * sumY + n *
// meanX * meanY;
double centeredSumXY = sumXY - meanY * sumX;
// double centeredSumX2 = sumX2 - 2.0 * meanX * sumX + n * meanX *
// meanX;
double centeredSumX2 = sumX2 - meanX * sumX;
// double centeredSumY2 = sumY2 - 2.0 * meanY * sumY + n * meanY *
// meanY;
double centeredSumY2 = sumY2 - meanY * sumY;
// result = computeResult(count, centeredSumXY, centeredSumX2,
// centeredSumY2, sumXYdiff2);
result = computeResult(count, sumXY, sumX2, sumY2, sumXYdiff2);
if (!Double.isNaN(result)) {
result = normalizeWeightResult(result, count,
dataModel.getNumUsers());
}
return result;
}
}

Calculating the Moment Of Inertia for a concave 2D polygon relative to its orgin

I want to compute the moment of inertia of a (2D) concave polygon. I found this on the internet. But I'm not very sure how to interpret the formula...
Formula http://img101.imageshack.us/img101/8141/92175941c14cadeeb956d8f.gif
1) Is this formula correct?
2) If so, is my convertion to C++ correct?
float sum (0);
for (int i = 0; i < N; i++) // N = number of vertices
{
int j = (i + 1) % N;
sum += (p[j].y - p[i].y) * (p[j].x + p[i].x) * (pow(p[j].x, 2) + pow(p[i].x, 2)) - (p[j].x - p[i].x) * (p[j].y + p[i].y) * (pow(p[j].y, 2) + pow(p[i].y, 2));
}
float inertia = (1.f / 12.f * sum) * density;
Martijn
#include <math.h> //for abs
float dot (vec a, vec b) {
return (a.x*b.x + a.y*b.y);
}
float lengthcross (vec a, vec b) {
return (abs(a.x*b.y - a.y*b.x));
}
...
do stuff
...
float sum1=0;
float sum2=0;
for (int n=0;n<N;++n) { //equivalent of the Σ
sum1 += lengthcross(P[n+1],P[n])*
(dot(P[n+1],P[n+1]) + dot(P[n+1],P[n]) + dot(P[n],P[n]));
sum2 += lengthcross(P[n+1],P[n]);
}
return (m/6*sum1/sum2);
Edit: Lots of small math changes
I think you have more work to do that merely translating formulas into code. You need to understand exactly what this formula means.
When you have a 2D polygon, you have three moments of inertia you can calculate relative to a given coordinate system: moment about x, moment about y, and polar moment of inertia. There's a parallel axis theorem that allows you to translate from one coordinate system to another.
Do you know precisely which moment and coordinate system this formula applies to?
Here's some code that might help you, along with a JUnit test to prove that it works:
import java.awt.geom.Point2D;
/**
* PolygonInertiaCalculator
* User: Michael
* Date: Jul 25, 2010
* Time: 9:51:47 AM
*/
public class PolygonInertiaCalculator
{
private static final int MIN_POINTS = 2;
public static double dot(Point2D u, Point2D v)
{
return u.getX()*v.getX() + u.getY()*v.getY();
}
public static double cross(Point2D u, Point2D v)
{
return u.getX()*v.getY() - u.getY()*v.getX();
}
/**
* Calculate moment of inertia about x-axis
* #param poly of 2D points defining a closed polygon
* #return moment of inertia about x-axis
*/
public static double ix(Point2D [] poly)
{
double ix = 0.0;
if ((poly != null) && (poly.length > MIN_POINTS))
{
double sum = 0.0;
for (int n = 0; n < (poly.length-1); ++n)
{
double twiceArea = poly[n].getX()*poly[n+1].getY() - poly[n+1].getX()*poly[n].getY();
sum += (poly[n].getY()*poly[n].getY() + poly[n].getY()*poly[n+1].getY() + poly[n+1].getY()*poly[n+1].getY())*twiceArea;
}
ix = sum/12.0;
}
return ix;
}
/**
* Calculate moment of inertia about y-axis
* #param poly of 2D points defining a closed polygon
* #return moment of inertia about y-axis
* #link http://en.wikipedia.org/wiki/Second_moment_of_area
*/
public static double iy(Point2D [] poly)
{
double iy = 0.0;
if ((poly != null) && (poly.length > MIN_POINTS))
{
double sum = 0.0;
for (int n = 0; n < (poly.length-1); ++n)
{
double twiceArea = poly[n].getX()*poly[n+1].getY() - poly[n+1].getX()*poly[n].getY();
sum += (poly[n].getX()*poly[n].getX() + poly[n].getX()*poly[n+1].getX() + poly[n+1].getX()*poly[n+1].getX())*twiceArea;
}
iy = sum/12.0;
}
return iy;
}
/**
* Calculate polar moment of inertia xy
* #param poly of 2D points defining a closed polygon
* #return polar moment of inertia xy
* #link http://en.wikipedia.org/wiki/Second_moment_of_area
*/
public static double ixy(Point2D [] poly)
{
double ixy = 0.0;
if ((poly != null) && (poly.length > MIN_POINTS))
{
double sum = 0.0;
for (int n = 0; n < (poly.length-1); ++n)
{
double twiceArea = poly[n].getX()*poly[n+1].getY() - poly[n+1].getX()*poly[n].getY();
sum += (poly[n].getX()*poly[n+1].getY() + 2.0*poly[n].getX()*poly[n].getY() + 2.0*poly[n+1].getX()*poly[n+1].getY() + poly[n+1].getX()*poly[n].getY())*twiceArea;
}
ixy = sum/24.0;
}
return ixy;
}
/**
* Calculate the moment of inertia of a 2D concave polygon
* #param poly array of 2D points defining the perimeter of the polygon
* #return moment of inertia
* #link http://www.physicsforums.com/showthread.php?t=43071
* #link http://www.physicsforums.com/showthread.php?t=25293
* #link http://stackoverflow.com/questions/3329383/help-me-with-converting-latex-formula-to-code
*/
public static double inertia(Point2D[] poly)
{
double inertia = 0.0;
if ((poly != null) && (poly.length > MIN_POINTS))
{
double numer = 0.0;
double denom = 0.0;
double scale;
double mag;
for (int n = 0; n < (poly.length-1); ++n)
{
scale = dot(poly[n + 1], poly[n + 1]) + dot(poly[n + 1], poly[n]) + dot(poly[n], poly[n]);
mag = Math.sqrt(cross(poly[n], poly[n+1]));
numer += mag * scale;
denom += mag;
}
inertia = numer / denom / 6.0;
}
return inertia;
}
}
Here's the JUnit test to accompany it:
import org.junit.Test;
import java.awt.geom.Point2D;
import static org.junit.Assert.assertEquals;
/**
* PolygonInertiaCalculatorTest
* User: Michael
* Date: Jul 25, 2010
* Time: 10:16:04 AM
*/
public class PolygonInertiaCalculatorTest
{
#Test
public void testTriangle()
{
Point2D[] poly =
{
new Point2D.Double(0.0, 0.0),
new Point2D.Double(1.0, 0.0),
new Point2D.Double(0.0, 1.0)
};
// Moment of inertia about the y1 axis
// http://www.efunda.com/math/areas/triangle.cfm
double expected = 1.0/3.0;
double actual = PolygonInertiaCalculator.inertia(poly);
assertEquals(expected, actual, 1.0e-6);
}
#Test
public void testSquare()
{
Point2D[] poly =
{
new Point2D.Double(0.0, 0.0),
new Point2D.Double(1.0, 0.0),
new Point2D.Double(1.0, 1.0),
new Point2D.Double(0.0, 1.0)
};
// Polar moment of inertia about z axis
// http://www.efunda.com/math/areas/Rectangle.cfm
double expected = 2.0/3.0;
double actual = PolygonInertiaCalculator.inertia(poly);
assertEquals(expected, actual, 1.0e-6);
}
#Test
public void testRectangle()
{
// This gives the moment of inertia about the y axis for a coordinate system
// through the centroid of the rectangle
Point2D[] poly =
{
new Point2D.Double(0.0, 0.0),
new Point2D.Double(4.0, 0.0),
new Point2D.Double(4.0, 1.0),
new Point2D.Double(0.0, 1.0)
};
double expected = 5.0 + 2.0/3.0;
double actual = PolygonInertiaCalculator.inertia(poly);
assertEquals(expected, actual, 1.0e-6);
double ix = PolygonInertiaCalculator.ix(poly);
double iy = PolygonInertiaCalculator.iy(poly);
double ixy = PolygonInertiaCalculator.ixy(poly);
assertEquals(ix, (1.0 + 1.0/3.0), 1.0e-6);
assertEquals(iy, (21.0 + 1.0/3.0), 1.0e-6);
assertEquals(ixy, 4.0, 1.0e-6);
}
}
For reference, here's a mutable 2D org.gcs.kinetic.Vector implementation and a more versatile, immutable org.jscience.mathematics.vector implementation. This article on Calculating a 2D Vector’s Cross Product is helpful, too.
I did it with Tesselation. And take the MOI's all together.

Categories