first of all i'd like to point out that i know this is a topic covered a lot but after about an hour of looking at other questions and trying what is suggested there i still can't get this to work.
I'm performing a binary search through Performances for numbers that are within 0.1 of a given number time. however, i need both the min/max targets and the number we are searching with (average) to be rounded to only one decimal place.
the method assumes that performance is sorted in ascending order.
public static int binarySearch(Performance[] performances, double time) {
if (performances == null){
return -1;
}
int first = 0;
int last = performances.length - 1;
double targetMax = time + 0.1;
double targetMin = time - 0.1;
targetMax = Math.round((targetMax * 100)) / 100.0;
targetMin = Math.round((targetMin * 100)) / 100.0;
while (first <= last){
int mid = (first + last)/2;
double average = performances[mid].averageTime();
average = Math.round((average * 100)) / 100.0;
if ((targetMax > average) && (targetMin < average) ){
return mid;
}
else if(average < targetMin){
last = mid -1;
}
else {
first = mid + 1;
}
}
return -1;
}
here's where it gets weird. the rounding i have done seems to work fine for targetMax and targetMin with 9.299999999 rounding to 9.3, however when rounding average down from 9.3333333333 it returns 9.33
i really am stumped on this one, aren't i doing the exact same thing to both variables?
new to this website so please excuse anything i've left out, just ask and ill edit it in. trying my best! :)
You're rounding both to two decimal places - it's just that 9.2999999 rounded is 9.30.
Change your 100s to 10 to round to a single decimal place in each case.
Related
I am currently working on a Java math library which will include a variety of correctly rounded functions (i.e. sqrt, cbrt, exp, sin, gamma, and ln). I have already used the Babylonian method to write a square root algorithm that is correct to within 1 ulp of the correct answer. However, I cannot figure out how to properly calculate which way the number should be rounded to represent the best possible approximation to the actual square root of the input. Answers containing principles which can be extended to other functions would be preferred, but I have heard that sqrt is a simpler case than many transcendental functions, and specialized solutions would also be much appreciated.
Also, here is a cleaned-up version of my code as of this question's original submission:
public static double sqrt(double x) {
long bits = Double.doubleToLongBits(x);
// NaN and non-zero negatives:
if (Double.isNaN(x) || x < 0) return Double.NaN;
// +-0 and 1:
if (x == 0d || x == 1d) return x;
// Halving the exponent to come up with a good initial guess:
long exp = bits << 1;
exp = (exp - 0x7fe0000000000000L >> 1) + 0x7fe0000000000000L >>> 1 & 0x7ff0000000000000L;
double guess = Double.longBitsToDouble(bits & 0x800fffffffffffffL | exp);
double nextUp, nextDown, guessSq, nextUpSq, nextDownSq;
// Main loop:
while (true) {
guessSq = guess * guess;
if (guessSq == x) return guess;
nextUp = Math.nextUp(guess);
nextUpSq = nextUp * nextUp;
if (nextUpSq == x) return nextUp;
if (guessSq < x && x < nextUpSq) {
double z = x / nextUp;
if (z * nextUp > x) z = Math.nextDown(z);
return z < nextUp ? nextUp : guess;
}
nextDown = Math.nextDown(guess);
nextDownSq = nextDown * nextDown;
if (nextDownSq == x) return nextDown;
if (nextDownSq < x && x < guessSq) {
double z = x / guess;
if (z * guess > x) z = Math.nextDown(z);
return z < guess ? guess : nextDown;
}
// Babylonian method:
guess = 0.5 * (guess + x / guess);
}
}
As you can see, I was using division as a test. However, I believe that requires the division to round towards 0, which obviously doesn't happen in Java.
By the Taylor theorem, the square root function is locally approximated by a linear function, of slope 1/2√x, which is positive. So you can relate the error to the error in the square, x - (√x)², where √x is understood to be the approximate root. Then you round in the direction that minimizes this error.
Anyway, the computation of x - (√x)² is subjected to catastrophic cancellation and you may need extended accuracy to compute it reliably. Not sure the benefit is worth the effort.
Im writing a function that implements the following expression (1/n!)*(1!+2!+3!+...+n!).
The function is passed the arguement n and I have to return the above statement as a double, truncated to the 6th decimal place. The issue im running into is that the factorial value becomes so large that it becomes infinity (for large values of n).
Here is my code:
public static double going(int n) {
double factorial = 1.00;
double result = 0.00, sum = 0.00;
for(int i=1; i<n+1; i++){
factorial *= i;
sum += factorial;
}
//Truncate decimals to 6 places
result = (1/factorial)*(sum);
long truncate = (long)Math.pow(10,6);
result = result * truncate;
long value = (long) result;
return (double) value / truncate;
}
Now, the above code works fine for say n=5 or n= 113, but anything above n = 170 and my factorial and sum expressions become infinity. Is my approach just not going to work due to the exponential growth of the numbers? And what would be a work around to calculating very large numbers that doesnt impact performance too much (I believe BigInteger is quite slow from looking at similar questions).
You can solve this without evaluating a single factorial.
Your formula simplifies to the considerably simpler, computationally speaking
1!/n! + 2!/n! + 3!/n! + ... + 1
Aside from the first and last terms, a lot of factors actually cancel, which will help the precision of the final result, for example for 3! / n! you only need to multiply 1 / 4 through to 1 / n. What you must not do is to evaluate the factorials and divide them.
If 15 decimal digits of precision is acceptable (which it appears that it is from your question) then you can evaluate this in floating point, adding the small terms first. As you develop the algorithm, you'll notice the terms are related, but be very careful how you exploit that as you risk introducing material imprecision. (I'd consider that as a second step if I were you.)
Here's a prototype implementation. Note that I accumulate all the individual terms in an array first, then I sum them up starting with the smaller terms first. I think it's computationally more accurate to start from the final term (1.0) and work backwards, but that might not be necessary for a series that converges so quickly. Let's do this thoroughly and analyse the results.
private static double evaluate(int n){
double terms[] = new double[n];
double term = 1.0;
terms[n - 1] = term;
while (n > 1){
terms[n - 2] = term /= n;
--n;
}
double sum = 0.0;
for (double t : terms){
sum += t;
}
return sum;
}
You can see how very quickly the first terms become insignificant. I think you only need a few terms to compute the result to the tolerance of a floating point double. Let's devise an algorithm to stop when that point is reached:
The final version. It seems that the series converges so quickly that you don't need to worry about adding small terms first. So you end up with the absolutely beautiful
private static double evaluate_fast(int n){
double sum = 1.0;
double term = 1.0;
while (n > 1){
double old_sum = sum;
sum += term /= n--;
if (sum == old_sum){
// precision exhausted for the type
break;
}
}
return sum;
}
As you can see, there is no need for BigDecimal &c, and certainly never a need to evaluate any factorials.
You could use BigDecimal like this:
public static double going(int n) {
BigDecimal factorial = BigDecimal.ONE;
BigDecimal sum = BigDecimal.ZERO;
BigDecimal result;
for(int i=1; i<n+1; i++){
factorial = factorial.multiply(new BigDecimal(i));
sum = sum.add(factorial);
}
//Truncate decimals to 6 places
result = sum.divide(factorial, 6, RoundingMode.HALF_EVEN);
return result.doubleValue();
}
I'm trying to understand reqursion, but I have found one task, I couldn't solve for few days already.
X = 1/1 + 1/(1*2) + 1/(1*2*3) + 1/(1*2*3*4) + 1/(1*2*3*4*5) .....
how can I solve it for 100 repeats without conditional operators?
Can it be solved without recursion?
I've tried this code, but it doesn't work correctly and it contains "If".
public static double harFac(double n) {
if (n == 1) return 1;
return (1.0 / (n * harFac(n - 1))) + harFac(n - 1);
}
I believe you could do something like this:
double result = 0;
int div = 1;
for (int i = 1; i <= 100; i++){
result += 1.0 / div; /*the division needs to take place in floating point*/
div *= i+1;
}
You'll very quickly run into trouble if you evaluate the denominator like that as it will run to a limit very quickly. When working with floating point, it's also a good idea to evaluate the smaller terms first.
Fortunately you can solve both of these problems by recasting the expression to
1 * (1 + 1/2 * ( 1 + 1/3 * (1 + 1/4 * ( ... ) ) ) )
So your final term is in the recursion is foo = 1 + 1.0/100, the penultimate term in the recursion is 1 + 1/98 * foo, and so on.
I personally wouldn't use recursion to solve this, rather use a loop in a single function.
You're along the right lines but you shouldn't be calling harFac twice. You need to instead calculate the divisor. I can't see how you would do this without an if condition, though.
public static double harFac(double n)
{
if (n == 1) return 1;
int divisor = 1;
for (int i = 2; i <= n; ++i) divisor *= i;
return (1.0 / divisor) + harFac(n - 1);
}
This doesn't work beyond around n = 30 because the divisor becomes so massive.
I'm having trouble with this program, we are supposed to compute pi to six significant figures, WITHOUT ROUNDING and WITHOUT using math library constant, the program should also show the number of iterations it took to reach 6 sig fig accuracy as well as the math constant in the output, so far I'm just trying to get my head around computing pi, I'm completely lost on how to get six 6 figs with or without rounding, not to mention how to iterate how many iterations it took to reach 6 sig figs pls help.
"Write an algorithm and program to compute π, using the formula described in the text PI/4 =1-(1/3)+(1/5)-(1/7)+(1/9)...." Output will include your computed value for π, the math library constant expected value for π and the number of iterations it took to reach six-significant digit accuracy. The number of iterations could exceed 250,000. Make your output clean and easy to read for comparing results.
This is the code I have so far to compute pi but even this I'm not sure is right.
public static void main(String[] args) throws Exception {
Double pi=1.0;
int s=1;
for (double j=3.0; j<100.0; j=j+2)
{
if (s % 2 == 0)
pi = pi + (1/j);
else
pi = pi - (1/j);
s = s + 1;
}
System.out.println(4*pi);
So there is presumably a way to make an a priori estimate of error using the alternating series theorem. But suppose you do not know the theorem or trust your math (if you do, just change 100.0 above to the right number. 800000.0 as estimated above would work, just barely). Here is something a little safer, perhaps, though it might be better to check the goodness of the estimate only every 1000 times through the loop, not each time?
Double pi=1.0; Boolean closeEnough=false;
int s=1;
for (double j=3.0; (!closeEnough); j=j+2)
{
if (s % 2 == 0)
pi = pi + (1/j);
else
pi = pi - (1/j);
if (Math.abs(4/(j+2))<0.000005)
closeEnough=true;
s = s + 1;
}
Ideally you should encapsulate your calculation in a class:
public class PI {
private double estimate = 1.0;
private int iteration = 0;
public double getEstimate() {
return 4 * estimate;
}
public void iterate() {
double ratio = 1.0 / (iteration * 2 + 3);
if (iteration % 2 == 0)
estimate -= ratio;
else
estimate += ratio;
iteration++;
}
}
Then the loop becomes pretty trivial:
PI pi = new PI();
while (Math.round(pi.getEstimate() * 1e5) != Math.round(Math.PI * 1e5))
pi.iterate();
For me this took 130,657 iterations
consider
String piStr = "3.14159";
Double pi=1.0;
int s=1;
double j=3.0;
String lcl = "";
String upToNCharacters = "";
while (true)
{
if (s % 2 == 0)
pi = pi + (1/j);
else
pi = pi - (1/j);
s = s + 1;
j=j+2;
lcl = "" + 4 * pi;
upToNCharacters = lcl.substring(0, Math.min(lcl.length(), 7));
if (upToNCharacters.equals(piStr)) {
break;
}
}
System.out.println(upToNCharacters);
System.out.println("after " + s);
output
3.14159
after 136121
Numbers are being stored in a database (out of my control) as floats/doubles etc.
When I pull them out they are damaged - for example 0.1 will come out (when formatted) as 0.100000001490116119384765625.
Is there a reliable way to recover these numbers?
I have tried new BigDecimal(((Number) o).doubleValue()) and BigDecimal.valueOf(((Number) o).doubleValue()) but these do not work. I still get the damaged result.
I am aware that I could make assumptions on the number of decimal places and round them but this will break for numbers that are deliberately 0.33333333333 for example.
Is there a simple method that will work for most rationals?
I suppose I am asking is there a simple way of finding the most minimal rational number that is within a small delta of a float number?.
you can store the numbers in the database as String and on the retrieval just parseDouble() them. This way the number wont be damaged, it will be same as you store there.
is there a simple way of finding a rational number that is within 0.00001 of a float number?.
This is called rounding.
double d = ((Number) o).doubleValue();
double d2 = Math.round(d * 1e5) / 1e5;
BigDecimal bd = BigDecimal.valueOf(d2);
or you can use BigDecimal to perform the rounding (I avoid using BigDecimal as it is needelessly slow once you know how to use rounding of doubles)
double d = ((Number) o).doubleValue();
BigDecimal bd = BigDecimal.valueOf(d).setScale(5, RoundingMode.HALF_UP);
Note: never use new BigDecimal(double) unless you understand what it does. Most likely BigDecial.valueOf(double) is what you wanted.
Here's the bludgeon way I have done it - I would welcome a more elegant solution.
I chose an implementation of Rational that had a mediant method ready-made for me.
I refactored it to use long instead of int and then added:
// Default delta to apply.
public static final double DELTA = 0.000001;
public static Rational valueOf(double dbl) {
return valueOf(dbl, DELTA);
}
// Create a good rational for the value within the delta supplied.
public static Rational valueOf(double dbl, double delta) {
// Primary checks.
if ( delta <= 0.0 ) {
throw new IllegalArgumentException("Delta must be > 0.0");
}
// Remove the integral part.
long integral = (long) Math.floor(dbl);
dbl -= integral;
// The value we are looking for.
final Rational d = new Rational((long) ((dbl) / delta), (long) (1 / delta));
// Min value = d - delta.
final Rational min = new Rational((long) ((dbl - delta) / delta), (long) (1 / delta));
// Max value = d + delta.
final Rational max = new Rational((long) ((dbl + delta) / delta), (long) (1 / delta));
// Start the fairey sequence.
Rational l = ZERO;
Rational h = ONE;
Rational found = null;
// Keep slicing until we arrive within the delta range.
do {
// Either between min and max -> found it.
if (found == null && min.compareTo(l) <= 0 && max.compareTo(l) >= 0) {
found = l;
}
if (found == null && min.compareTo(h) <= 0 && max.compareTo(h) >= 0) {
found = h;
}
if (found == null) {
// Make the mediant.
Rational m = mediant(l, h);
// Replace either l or h with mediant.
if (m.compareTo(d) < 0) {
l = m;
} else {
h = m;
}
}
} while (found == null);
// Bring back the sign and the integral.
if (integral != 0) {
found = found.plus(new Rational(integral, 1));
}
// That's me.
return found;
}
public BigDecimal toBigDecimal() {
// Do it to just 4 decimal places.
return toBigDecimal(4);
}
public BigDecimal toBigDecimal(int digits) {
// Do it to n decimal places.
return new BigDecimal(num).divide(new BigDecimal(den), digits, RoundingMode.DOWN).stripTrailingZeros();
}
Essentially - the algorithm starts with a range of 0-1. At each iteration I check to see if either end of the range falls between my d-delta - d+delta range. If it does we've found an answer.
If no answer is found we take the mediant of the two limits and replace one of the limits with it. The limit to replace is chosen to ensure the limits surround d at all times.
This is essentially doing a binary-chop search between 0 and 1 to find the first rational that falls within the desired range.
Mathematically I climb down the Stern-Brocot Tree choosing the branch that keeps me enclosing the desired number until I fall into the desired delta.
NB: I have not finished my testing but it certainly finds 1/10 for my input of 0.100000001490116119384765625 and 1/3 for 1.0/3.0 and the classic 355/113 for π.