Related
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 was trying to get a cubic root in java using Math.pow(n, 1.0/3) but because it divides doubles, it doesn't return the exact answer. For example, with 125, this gives 4.9999999999. Is there a work-around for this? I know there is a cubic root function but I'd like to fix this so I can calculate higher roots.
I would not like to round because I want to know whether a number has an integer root by doing something like this: Math.pow(n, 1.0 / 3) % ((int) Math.pow(n, 1.0 / 3)).
Since it is not possible to have arbitrary-precision calculus with double, you have three choices:
Define a precision for which you decide whether a double value is an integer or not.
Test whether the rounded value of the double you have is a correct result.
Do calculus on a BigDecimal object, which supports arbitrary-precision double values.
Option 1
private static boolean isNthRoot(int value, int n, double precision) {
double a = Math.pow(value, 1.0 / n);
return Math.abs(a - Math.round(a)) < precision; // if a and round(a) are "close enough" then we're good
}
The problem with this approach is how to define "close enough". This is a subjective question and it depends on your requirements.
Option 2
private static boolean isNthRoot(int value, int n) {
double a = Math.pow(value, 1.0 / n);
return Math.pow(Math.round(a), n) == value;
}
The advantage of this method is that there is no need to define a precision. However, we need to perform another pow operation so this will affect performance.
Option 3
There is no built-in method to calculate a double power of a BigDecimal. This question will give you insight on how to do it.
The Math.round function will round to the nearest long value that can be stored to a double. You could compare the 2 results to see if the number has an integer cubic root.
double dres = Math.pow(125, 1.0 / 3.0);
double ires = Math.round(dres);
double diff = Math.abs(dres - ires);
if (diff < Math.ulp(10.0)) {
// has cubic root
}
If that's inadequate you can try implementing this algorithm and stop early if the result doesn't seem to be an integer.
I wrote this method to compute floor(x^(1/n)) where x is a non-negative BigInteger and n is a positive integer. It was a while ago now so I can't explain why it works, but I'm reasonably confident that when I wrote it I was happy that it's guaranteed to give the correct answer reasonably quickly.
To see if x is an exact n-th power you can check if the result raised to the power n gives you exactly x back again.
public static BigInteger floorOfNthRoot(BigInteger x, int n) {
int sign = x.signum();
if (n <= 0 || (sign < 0))
throw new IllegalArgumentException();
if (sign == 0)
return BigInteger.ZERO;
if (n == 1)
return x;
BigInteger a;
BigInteger bigN = BigInteger.valueOf(n);
BigInteger bigNMinusOne = BigInteger.valueOf(n - 1);
BigInteger b = BigInteger.ZERO.setBit(1 + x.bitLength() / n);
do {
a = b;
b = a.multiply(bigNMinusOne).add(x.divide(a.pow(n - 1))).divide(bigN);
} while (b.compareTo(a) == -1);
return a;
}
To use it:
System.out.println(floorOfNthRoot(new BigInteger("125"), 3));
Edit
Having read the comments above I now remember that this is the Newton-Raphson method for n-th roots. The Newton-Raphson method has quadratic convergence (which in everyday language means it's fast). You can try it on numbers which have dozens of digits and you should get the answer in a fraction of a second.
You can adapt the method to work with other number types, but double and BigDecimal are in my view not suited for this kind of thing.
You can use some tricks come from mathematics field, to havemore accuracy.
Like this one x^(1/n) = e^(lnx/n).
Check the implementation here:
https://www.baeldung.com/java-nth-root
Here is the solution without using Java's Math.pow function.
It will give you nearly nth root
public class NthRoot {
public static void main(String[] args) {
try (Scanner scanner = new Scanner(System.in)) {
int testcases = scanner.nextInt();
while (testcases-- > 0) {
int root = scanner.nextInt();
int number = scanner.nextInt();
double rootValue = compute(number, root) * 1000.0 / 1000.0;
System.out.println((int) rootValue);
}
} catch (Exception e) {
e.printStackTrace();
}
}
private static double compute(int number, int root) {
double xPre = Math.random() % 10;
double error = 0.0000001;
double delX = 2147483647;
double current = 0.0;
while (delX > error) {
current = ((root - 1.0) * xPre + (double) number / Math.pow(xPre, root - 1)) / (double) root;
delX = Math.abs(current - xPre);
xPre = current;
}
return current;
}
I'd go for implementing my own function to do this, possibly based on this method.
Well this is a good option to choose in this situation.
You can rely on this-
System.out.println(" ");
System.out.println(" Enter a base and then nth root");
while(true)
{
a=Double.parseDouble(br.readLine());
b=Double.parseDouble(br.readLine());
double negodd=-(Math.pow((Math.abs(a)),(1.0/b)));
double poseve=Math.pow(a,(1.0/b));
double posodd=Math.pow(a,(1.0/b));
if(a<0 && b%2==0)
{
String io="\u03AF";
double negeve=Math.pow((Math.abs(a)),(1.0/b));
System.out.println(" Root is imaginary and value= "+negeve+" "+io);
}
else if(a<0 && b%2==1)
System.out.println(" Value= "+negodd);
else if(a>0 && b%2==0)
System.out.println(" Value= "+poseve);
else if(a>0 && b%2==1)
System.out.println(" Value= "+posodd);
System.out.println(" ");
System.out.print(" Enter '0' to come back or press any number to continue- ");
con=Integer.parseInt(br.readLine());
if(con==0)
break;
else
{
System.out.println(" Enter a base and then nth root");
continue;
}
}
It's a pretty ugly hack, but you could reach a few of them through indenting.
System.out.println(Math.sqrt(Math.sqrt(256)));
System.out.println(Math.pow(4, 4));
System.out.println(Math.pow(4, 9));
System.out.println(Math.cbrt(Math.cbrt(262144)));
Result:
4.0
256.0
262144.0
4.0
Which will give you every n^3th cube and every n^2th root.
Find nth root Using binary search method.
Here is the way to find nth root with any precision according to your requirements.
import java.util.Scanner;
public class FindRoot {
public static void main(String[] args) {
try (Scanner scanner = new Scanner(System.in)) {
int testCase = scanner.nextInt();
while (testCase-- > 0) {
double number = scanner.nextDouble();
int root = scanner.nextInt();
double precision = scanner.nextDouble();
double result = findRoot(number, root, precision);
System.out.println(result);
}
}
}
private static double findRoot(double number, int root, double precision) {
double start = 0;
double end = number / 2;
double mid = end;
while (true) {
if (precision >= diff(number, mid, root)) {
return mid;
}
if (pow(mid, root) > number) {
end = mid;
} else {
start = mid;
}
mid = (start + end) / 2;
}
}
private static double diff(double number, double mid, int n) {
double power = pow(mid, n);
return number > power ? number - power : power - number;
}
private static double pow(double number, int pow) {
double result = number;
while (pow-- > 1) {
result *= number;
}
return result;
}
}
I'm using this nth_root algorithm, which also provide the remainder :
public static BigInteger[] sqrt(final BigInteger n) {
final BigInteger[] res = {ZERO, n,};
BigInteger a, b;
assert (n.signum() > 0);
a = ONE.shiftLeft(n.bitLength() & ~1);
while (!a.equals(ZERO)) {
b = res[0].add(a);
res[0] = res[0].shiftRight(1);
if (res[1].compareTo(b) >= 0) {
res[1] = res[1].subtract(b);
res[0] = res[0].add(a);
}
a = a.shiftRight(2);
}
return res;
}
public static BigInteger[] nth_root(BigInteger n, final int nth) {
final BigInteger[] res;
switch(nth){
case 0 : res = new BigInteger[]{n.equals(ONE) ? ONE : ZERO, ZERO} ; break;
case 1 : res = new BigInteger[]{n, ZERO}; break;
case 2 : res = sqrt(n); break;
default:
int sign = n.signum() ;
n = n.abs();
res = new BigInteger[]{n.shiftLeft((n.bitLength() + nth - 1) / nth), n};
while(res[1].compareTo(res[0])<0) {
res[0] = res[1];
res[1] = BigInteger.valueOf(nth-1).multiply(res[1]).add(n.divide(res[1].pow(nth - 1))).divide(BigInteger.valueOf(nth));
}
res[1] = res[0].pow(nth);
res[1] = n.subtract(res[1]);
if (sign < 0 && (nth & 1) == 1) {
res[0] = res[0].negate();
res[1] = res[1].negate();
} else assert (sign > 0);
}
return res ;
}
}
Note: Updated on 06/17/2015. Of course this is possible. See the solution below.
Even if anyone copies and pastes this code, you still have a lot of cleanup to do. Also note that you will have problems inside the critical strip from Re(s) = 0 to Re(s) = 1 :). But this is a good start.
import java.util.Scanner;
public class NewTest{
public static void main(String[] args) {
RiemannZetaMain func = new RiemannZetaMain();
double s = 0;
double start, stop, totalTime;
Scanner scan = new Scanner(System.in);
System.out.print("Enter the value of s inside the Riemann Zeta Function: ");
try {
s = scan.nextDouble();
}
catch (Exception e) {
System.out.println("You must enter a positive integer greater than 1.");
}
start = System.currentTimeMillis();
if (s <= 0)
System.out.println("Value for the Zeta Function = " + riemannFuncForm(s));
else if (s == 1)
System.out.println("The zeta funxtion is undefined for Re(s) = 1.");
else if(s >= 2)
System.out.println("Value for the Zeta Function = " + getStandardSum(s));
else
System.out.println("Value for the Zeta Function = " + getNewSum(s));
stop = System.currentTimeMillis();
totalTime = (double) (stop-start) / 1000.0;
System.out.println("Total time taken is " + totalTime + " seconds.");
}
// Standard form the the Zeta function.
public static double standardZeta(double s) {
int n = 1;
double currentSum = 0;
double relativeError = 1;
double error = 0.000001;
double remainder;
while (relativeError > error) {
currentSum = Math.pow(n, -s) + currentSum;
remainder = 1 / ((s-1)* Math.pow(n, (s-1)));
relativeError = remainder / currentSum;
n++;
}
System.out.println("The number of terms summed was " + n + ".");
return currentSum;
}
public static double getStandardSum(double s){
return standardZeta(s);
}
//New Form
// zeta(s) = 2^(-1+2 s)/((-2+2^s) Gamma(1+s)) integral_0^infinity t^s sech^2(t) dt for Re(s)>-1
public static double Integrate(double start, double end) {
double currentIntegralValue = 0;
double dx = 0.0001d; // The size of delta x in the approximation
double x = start; // A = starting point of integration, B = ending point of integration.
// Ending conditions for the while loop
// Condition #1: The value of b - x(i) is less than delta(x).
// This would throw an out of bounds exception.
// Condition #2: The value of b - x(i) is greater than 0 (Since you start at A and split the integral
// up into "infinitesimally small" chunks up until you reach delta(x)*n.
while (Math.abs(end - x) >= dx && (end - x) > 0) {
currentIntegralValue += function(x) * dx; // Use the (Riemann) rectangle sums at xi to compute width * height
x += dx; // Add these sums together
}
return currentIntegralValue;
}
private static double function(double s) {
double sech = 1 / Math.cosh(s); // Hyperbolic cosecant
double squared = Math.pow(sech, 2);
return ((Math.pow(s, 0.5)) * squared);
}
public static double getNewSum(double s){
double constant = Math.pow(2, (2*s)-1) / (((Math.pow(2, s)) -2)*(gamma(1+s)));
return constant*Integrate(0, 1000);
}
// Gamma Function - Lanczos approximation
public static double gamma(double s){
double[] p = {0.99999999999980993, 676.5203681218851, -1259.1392167224028,
771.32342877765313, -176.61502916214059, 12.507343278686905,
-0.13857109526572012, 9.9843695780195716e-6, 1.5056327351493116e-7};
int g = 7;
if(s < 0.5) return Math.PI / (Math.sin(Math.PI * s)*gamma(1-s));
s -= 1;
double a = p[0];
double t = s+g+0.5;
for(int i = 1; i < p.length; i++){
a += p[i]/(s+i);
}
return Math.sqrt(2*Math.PI)*Math.pow(t, s+0.5)*Math.exp(-t)*a;
}
//Binomial Co-efficient - NOT CURRENTLY USING
/*
public static double binomial(int n, int k)
{
if (k>n-k)
k=n-k;
long b=1;
for (int i=1, m=n; i<=k; i++, m--)
b=b*m/i;
return b;
} */
// Riemann's Functional Equation
// Tried this initially and utterly failed.
public static double riemannFuncForm(double s) {
double term = Math.pow(2, s)*Math.pow(Math.PI, s-1)*(Math.sin((Math.PI*s)/2))*gamma(1-s);
double nextTerm = Math.pow(2, (1-s))*Math.pow(Math.PI, (1-s)-1)*(Math.sin((Math.PI*(1-s))/2))*gamma(1-(1-s));
double error = Math.abs(term - nextTerm);
if(s == 1.0)
return 0;
else
return Math.pow(2, s)*Math.pow(Math.PI, s-1)*(Math.sin((Math.PI*s)/2))*gamma(1-s)*standardZeta(1-s);
}
}
Ok well we've figured out that for this particular function, since this form of it isn't actually a infinite series, we cannot approximate using recursion. However the infinite sum of the Riemann Zeta series (1\(n^s) where n = 1 to infinity) could be solved through this method.
Additionally this method could be used to find any infinite series' sum, product, or limit.
If you execute the code your currently have, you'll get infinite recursion as 1-(1-s) = s (e.g. 1-s = t, 1-t = s so you'll just switch back and forth between two values of s infinitely).
Below I talk about the sum of series. It appears you are calculating the product of the series instead. The concepts below should work for either.
Besides this, the Riemann Zeta Function is an infinite series. This means that it only has a limit, and will never reach a true sum (in finite time) and so you cannot get an exact answer through recursion.
However, if you introduce a "threshold" factor, you can get an approximation that is as good as you like. The sum will increase/decrease as each term is added. Once the sum stabilizes, you can quit out of recursion and return your approximate sum. "Stabilized" is defined using your threshold factor. Once the sum varies by an amount less than this threshold factor (which you have defined), your sum has stabilized.
A smaller threshold leads to a better approximation, but also longer computation time.
(Note: this method only works if your series converges, if it has a chance of not converging, you might also want to build in a maxSteps variable to cease execution if the series hasn't converged to your satisfaction after maxSteps steps of recursion.)
Here's an example implementation, note that you'll have to play with threshold and maxSteps to determine appropriate values:
/* Riemann's Functional Equation
* threshold - if two terms differ by less than this absolute amount, return
* currSteps/maxSteps - if currSteps becomes maxSteps, give up on convergence and return
* currVal - the current product, used to determine threshold case (start at 1)
*/
public static double riemannFuncForm(double s, double threshold, int currSteps, int maxSteps, double currVal) {
double nextVal = currVal*(Math.pow(2, s)*Math.pow(Math.PI, s-1)*(Math.sin((Math.PI*s)/2))*gamma(1-s)); //currVal*term
if( s == 1.0)
return 0;
else if ( s == 0.0)
return -0.5;
else if (Math.abs(currVal-nextVal) < threshold) //When a term will change the current answer by less than threshold
return nextVal; //Could also do currVal here (shouldn't matter much as they differ by < threshold)
else if (currSteps == maxSteps)//When you've taken the max allowed steps
return nextVal; //You might want to print something here so you know you didn't converge
else //Otherwise just keep recursing
return riemannFuncForm(1-s, threshold, ++currSteps, maxSteps, nextVal);
}
}
This is not possible.
The functional form of the Riemann Zeta Function is --
zeta(s) = 2^s pi^(-1+s) Gamma(1-s) sin((pi s)/2) zeta(1-s)
This is different from the standard equation in which an infinite sum is measured from 1/k^s for all k = 1 to k = infinity. It is possible to write this as something similar to --
// Standard form the the Zeta function.
public static double standardZeta(double s) {
int n = 1;
double currentSum = 0;
double relativeError = 1;
double error = 0.000001;
double remainder;
while (relativeError > error) {
currentSum = Math.pow(n, -s) + currentSum;
remainder = 1 / ((s-1)* Math.pow(n, (s-1)));
relativeError = remainder / currentSum;
n++;
}
System.out.println("The number of terms summed was " + n + ".");
return currentSum;
}
The same logic doesn't apply to the functional equation (it isn't a direct sum, it is a mathematical relationship). This would require a rather clever way of designing a program to calculate negative values of Zeta(s)!
The literal interpretation of this Java code is ---
// Riemann's Functional Equation
public static double riemannFuncForm(double s) {
double currentVal = (Math.pow(2, s)*Math.pow(Math.PI, s-1)*(Math.sin((Math.PI*s)/2))*gamma(1-s));
if( s == 1.0)
return 0;
else if ( s == 0.0)
return -0.5;
else
System.out.println("Value of next value is " + nextVal(1-s));
return currentVal;//*nextVal(1-s);
}
public static double nextVal(double s)
{
return (Math.pow(2, s)*Math.pow(Math.PI, s-1)*(Math.sin((Math.PI*s)/2))*gamma(1-s));
}
public static double getRiemannSum(double s) {
return riemannFuncForm(s);
}
Testing on three or four values shows that this doesn't work. If you write something similar to --
// Riemann's Functional Equation
public static double riemannFuncForm(double s) {
double currentVal = Math.pow(2, s)*Math.pow(Math.PI, s-1)*(Math.sin((Math.PI*s)/2))*gamma(1-s); //currVal*term
if( s == 1.0)
return 0;
else if ( s == 0.0)
return -0.5;
else //Otherwise just keep recursing
return currentVal * nextVal(1-s);
}
public static double nextVal(double s)
{
return (Math.pow(2, s)*Math.pow(Math.PI, s-1)*(Math.sin((Math.PI*s)/2))*gamma(1-s));
}
I was misinterpretation how to do this through mathematics. I will have to use a different approximation of the zeta function for values less than 2.
I think I need to use a different form of the zeta function. When I run the entire program ---
import java.util.Scanner;
public class Test4{
public static void main(String[] args) {
RiemannZetaMain func = new RiemannZetaMain();
double s = 0;
double start, stop, totalTime;
Scanner scan = new Scanner(System.in);
System.out.print("Enter the value of s inside the Riemann Zeta Function: ");
try {
s = scan.nextDouble();
}
catch (Exception e) {
System.out.println("You must enter a positive integer greater than 1.");
}
start = System.currentTimeMillis();
if(s >= 2)
System.out.println("Value for the Zeta Function = " + getStandardSum(s));
else
System.out.println("Value for the Zeta Function = " + getRiemannSum(s));
stop = System.currentTimeMillis();
totalTime = (double) (stop-start) / 1000.0;
System.out.println("Total time taken is " + totalTime + " seconds.");
}
// Standard form the the Zeta function.
public static double standardZeta(double s) {
int n = 1;
double currentSum = 0;
double relativeError = 1;
double error = 0.000001;
double remainder;
while (relativeError > error) {
currentSum = Math.pow(n, -s) + currentSum;
remainder = 1 / ((s-1)* Math.pow(n, (s-1)));
relativeError = remainder / currentSum;
n++;
}
System.out.println("The number of terms summed was " + n + ".");
return currentSum;
}
public static double getStandardSum(double s){
return standardZeta(s);
}
// Riemann's Functional Equation
public static double riemannFuncForm(double s, double threshold, double currSteps, int maxSteps) {
double term = Math.pow(2, s)*Math.pow(Math.PI, s-1)*(Math.sin((Math.PI*s)/2))*gamma(1-s);
//double nextTerm = Math.pow(2, (1-s))*Math.pow(Math.PI, (1-s)-1)*(Math.sin((Math.PI*(1-s))/2))*gamma(1-(1-s));
//double error = Math.abs(term - nextTerm);
if(s == 1.0)
return 0;
else if (s == 0.0)
return -0.5;
else if (term < threshold) {//The recursion will stop once the term is less than the threshold
System.out.println("The number of steps is " + currSteps);
return term;
}
else if (currSteps == maxSteps) {//The recursion will stop if you meet the max steps
System.out.println("The series did not converge.");
return term;
}
else //Otherwise just keep recursing
return term*riemannFuncForm(1-s, threshold, ++currSteps, maxSteps);
}
public static double getRiemannSum(double s) {
double threshold = 0.00001;
double currSteps = 1;
int maxSteps = 1000;
return riemannFuncForm(s, threshold, currSteps, maxSteps);
}
// Gamma Function - Lanczos approximation
public static double gamma(double s){
double[] p = {0.99999999999980993, 676.5203681218851, -1259.1392167224028,
771.32342877765313, -176.61502916214059, 12.507343278686905,
-0.13857109526572012, 9.9843695780195716e-6, 1.5056327351493116e-7};
int g = 7;
if(s < 0.5) return Math.PI / (Math.sin(Math.PI * s)*gamma(1-s));
s -= 1;
double a = p[0];
double t = s+g+0.5;
for(int i = 1; i < p.length; i++){
a += p[i]/(s+i);
}
return Math.sqrt(2*Math.PI)*Math.pow(t, s+0.5)*Math.exp(-t)*a;
}
//Binomial Co-efficient
public static double binomial(int n, int k)
{
if (k>n-k)
k=n-k;
long b=1;
for (int i=1, m=n; i<=k; i++, m--)
b=b*m/i;
return b;
}
}
I notice that plugging in zeta(-1) returns -
Enter the value of s inside the Riemann Zeta Function: -1
The number of steps is 1.0
Value for the Zeta Function = -0.0506605918211689
Total time taken is 0.0 seconds.
I knew that this value was -1/12. I checked some other values with wolfram alpha and observed that --
double term = Math.pow(2, s)*Math.pow(Math.PI, s-1)*(Math.sin((Math.PI*s)/2))*gamma(1-s);
Returns the correct value. It is just that I am multiplying this value every time by zeta(1-s). In the case of Zeta(1/2), this will always multiply the result by 0.99999999.
Enter the value of s inside the Riemann Zeta Function: 0.5
The series did not converge.
Value for the Zeta Function = 0.999999999999889
Total time taken is 0.006 seconds.
I am going to see if I can replace the part for --
else if (term < threshold) {//The recursion will stop once the term is less than the threshold
System.out.println("The number of steps is " + currSteps);
return term;
}
This difference is the error between two terms in the summation. I may not be thinking about this correctly, it is 1:16am right now. Let me see if I can think better tomorrow ....
I am developing a simple Taxi Meter Calculator system. I have no idea what to use to implement it. I have written a code but got stuck at IF statement where I had to insert an array variable. I am not sure whether this is the correct way to implement it.
This is the logic.
The first Km is 50/-.
Then the next 10Km will be charged 45/- per Km. eg : if 2km were gone
, charges would be 50/- + 45/- = 95/-, if 3km were gone 140/-.
The next 10km will be charged 35/- per km
25/- per km will be charged no matter how many kms gone after the above 10km exceed.
This is the code I have coded so far
private void btn_calActionPerformed(java.awt.event.ActionEvent evt) {
int kms1 = 50;
int kms2 = 45;
int kms3 = 35;
int kms4 = 25;
String[] firstkm={"3,4,5,6,7,8,9,10,11"};
if(txt_km.getText().equals("1")){
lblout.setText(""+kms1);
}
if(txt_km.getText().equals("2")){
lblout.setText(""+(kms1+kms2));
}if(txt_km.getText().equals(firstkm)){
int get = Integer.parseInt(txt_km.getText());
int rate = get+kms2;
lblout.setText(""+rate);
}
}
if there is any other method to solve this problem please mention it.
int fare = 0;
int distance = 0;
if (distance > 21) {
fare += (distance - 21) * 25;
distance = 21;
}
if (distance > 11) {
fare += (distance - 11) * 35;
distance = 11;
}
if (distance > 1) {
fare += (distance - 1) * 45;
distance = 1;
}
if (distance > 0) {
fare += distance * 50;
}
Then refactor by putting the magic numbers into arrays and loop through the arrays (4 times).
Here's a hint: Implement this method
/**
This method returns the amount a passenger must pay for this kilometer of their trip
*/
public int chargeForKilometer(int kilometerNumberInTrip) {
//...
}
try
String[] firstkm={3,4,5,6,7,8,9,10,11};
if(txt_km.getText().equals(firstkm[1])){
lblout.setText(""+kms1);
}
....
In case your conditions change and you want to avoid adding if conditions in your code, I wrote a configurable code.
public int calculateRate(int kmCount){
int baseRate = 50;
int[] stepRate = {45,35};
int step = 10;
int fare = 0;
int threshold = 21;
int beyondThresholdRate = 25;
if(kmCount>0){
fare = baseRate;
fare += (kmCount - threshold)<0?0:(kmCount - threshold)*beyondThresholdRate;
kmCount = kmCount - 1;
for(int i=0;i<=((kmCount/step) + (kmCount%step>0?1:0));i++){
fare += (kmCount/step)==0?(kmCount%step)*stepRate[i]:step*stepRate[i];
kmCount -=step;
if(i==stepRate.length-1) break;
}
}
return fare;
}
It is slightly complex, however, flexible.
public double getDamage(double distance){
int damage1 = 30; // (0 - 38.1)
int damage2 = 20; // (50.8 - *)
double range1 = 38.1;
double range2 = 50.8;
double damage = 0; // FORMULA
return damage;
}
I try to create a formula to calculate the amount of damage that has been effected by the distance.
(Variable Distance =)
0 till 38.1 metre It will return 30 damage.
50.8 till Inifite it will return 20 damage.
38.1 till 50.8 it will decrease linear 30 -> 20.
How can I make this method work?
Thanks in advance.
Sounds like this:
double x = (distance - range1) / (range2 - range1);
if (x < 0)
x = 0;
if (x > 1)
x = 1;
return damage1 + x * (damage2 - damage1);
Basically you follow a linear rule and also adjust to stay in your linear interval.
Looks like you want a step formula, not a linear formula. Step formula is basically a bunch of if-else if comparisons in code. Something like this:
public double getDamage(double dist){
if (0 < dist & dist < 38.1)
return 30;
else if ( 38.1 < dist & dist < 50.8 )
return 30 - dist/10;
else
return
}
Edit: just saw you do want it linearly between 38.1 and 50.8.
Use something like this return 30 - dist/10; dist/10 would give you damage of 27 to 23, you'd need to find an appropriate constant (instead of 10) yourself. (Which is easy since its y = mx + b and you have two points by your conditions (38.1, 30) and (50.8, 20). So sub those into y = mx+b and you'll get the formula to use in the 2nd else-if.
The formula you are looking for is a simple variation of the point-slop equation y = m(x-x1) + y1 equation, where m = (damage1 - damage2)/(range1 - range2), x1 = range1, y1 = damage1, and x is the variable distance.
public double getDamage(double distance){
int damage1 = 30;
int damage2 = 20;
double range1 = 38.1;
double range2 = 50.8;
double damage = 0;
if(0 <= distance && distance <= range1)
damage = damage1;
else if (range1 < distance && distance < range2)
damage = (damage1 - damage2)/(range1 - range2) * (distance - range1) + damage1;
else if (distance >= range2)
damage = damage2;
return damage;
}