Check if a double = 1/3 - java

I have made a function that converts a double to a simplified fraction in Java:
public static int gcm(int a, int b) {
return b == 0 ? a : gcm(b, a % b);
}
public static String toFraction(double d) {
int decimals = String.valueOf(d).split("\\.")[1].length();
int mult = (int) Math.pow(10, decimals);
int numerator = (int) (d * mult);
int denominator = mult;
// now simplify
int gcm = gcm(numerator, denominator);
numerator /= gcm;
denominator /= gcm;
return numerator + "/" + denominator;
}
It works, except for the fact that if I use toFraction(1.0/3), this will, understandably, return "715827882/2147483647". How may I fix this to return "1/3"?

You have to allow for a certain error and not all fractions can be exactly represented as scalar values.
public static String toFraction(double d, double err) {
String s = Long.toString((long) d);
d -= (long) d;
if (d > err) {
for (int den = 2, max = (int) (1 / err); den < max; den++) {
long num = Math.round(d * den);
double d2 = (double) num / den;
if (Math.abs(d - d2) <= err)
return (s.equals("0") ? "" : s + " ") + num +"/"+den;
}
}
return s;
}
public static void main(String... args) {
System.out.println(toFraction(1.0/3, 1e-6));
System.out.println(toFraction(1.23456789, 1e-6));
System.out.println(toFraction(Math.E, 1e-6));
System.out.println(toFraction(Math.PI, 1e-6));
for (double d = 10; d < 1e15; d *= 10)
System.out.println(toFraction(Math.PI, 1.0 / d));
}
prints
1/3
1 19/81
2 719/1001
3 16/113
3 1/5
3 1/7
3 9/64
3 15/106
3 16/113
3 16/113
3 3423/24175
3 4543/32085
3 4687/33102
3 14093/99532
3 37576/265381
3 192583/1360120
3 244252/1725033
3 2635103/18610450
Note: this finds the 21/7, 333/106 and 355/113 approximations for PI.

No double value is equal to one third, so the only way your program can be made to print 1/3 is if you change the specification of the method to favour "nice" answers rather than the answer that is technically correct.
One thing you could do is choose a maximum denominator for the answers, say 100, and return the closest fraction with denominator 100 or less.
Here is how you could implement this using Java 8 streams:
public static String toFraction(double val) {
int b = IntStream.rangeClosed(1, 100)
.boxed()
.min(Comparator.comparingDouble(n -> Math.abs(val * n - Math.round(val * n))))
.get();
int a = (int) Math.round(val * b);
int h = gcm(a, b);
return a/h + "/" + b/h;
}
There is no nice approach to this. double is not very good for this sort of thing. Note that BigDecimal can't represent 1/3 either, so you'll have the same problem with that class.

There are nice ways to handle this but you will need to look at special cases. For example, if the numerator is 1 then the fraction is already reduced and you simply strip out the decimal places and return what you were given.

Related

Simple code doesn't output all required results

I have Java code that does the following:
1. Works with all combinations of integers a,b from 2 to 100 in sets of two. For instance, 2,2, 2,3,...,100,100. I just use two for loops for that.
2. For each set, checks whether the gcd of both integers is 1 (ignores sets where the gcd is 2 or more). I use the BigInteger Class because it has a method for that.
3. If the gcd is 1, check whether each of the two integers can be reconciled into a perfect power of base2 or more and exponent 3 or more. This is how I do that: For instance, let's consider the set 8,27. First, the code finds the max of the two. Then, for this set, the maximum power we can check for is Math.log10(27)/Math.log10(2) because the least the base can be is 2. This is just a trick from the field of mathematics. Hold that in variable powlim. I then use a for loop and Math.pow to check if all of the two integers have perfect nth roots like so;
for (double power = 3; power <= powlim; power++) {
double roota = Math.pow(a, 1.0 / power);
double rootb = Math.pow(b, 1.0 / power);
if ((Math.pow(Math.round(roota), power) == a) == true &&
(Math.pow(Math.round(rootb), power) == b) == true) {
if (a < b) {
System.out.println(a + "\t" + b);
}
}
The a<b condition makes sure that I don't get duplicate values such as both 8,27 and 27,8. For my purposes, the two are one and the same thing. Below is the entire code:
public static void main(String[] args) {
for (int a = 2; a <= 100; a++) {
for (int b = 2; b <= 100; b++) {
BigInteger newa = BigInteger.valueOf(a);
BigInteger newb = BigInteger.valueOf(b);
BigInteger thegcd = newa.gcd(newb);
if (thegcd.compareTo(BigInteger.ONE) == 0) {
double highest = Math.max(a, b);
double powlim = (Math.log10(highest) / Math.log10(2.0));
for (double power = 3; power <= powlim; power++) {
double roota = Math.pow(a, 1.0 / power);
double rootb = Math.pow(b, 1.0 / power);
if ((Math.pow(Math.round(roota), power) == a) == true
&& (Math.pow(Math.round(rootb), power) == b) == true {
if (a < b) {
System.out.println(a + "\t" + b);
}
}
}
}
}
}
}
So far so good. The code works fine. However, some few outputs that meet all the above criteria are ignored. For instance, when I run the above code I get;
8,27
16,81
27,64
What I don't understand is why a set like 8,81 is ignored. Its gcd is 1 and both of those integers can be expressed as perfect powers of base 2 or more and exponent 3 or more. 8 is 2^3 and 27 is 3^3. Why does this happen? Alternatively, it's fine if you provide your very own code that accomplishes the same task. I need to investigate how rare (or common) such sets are.
Math.pow(b, 1.0 / power); for 81 is 4.32
Then you round 4.32, and 4 at the power 3 is 64. 64 is not equal to 81.
What you should be doing is: Math.round(Math.pow(roota, power)) == a
Also, you need to iterate trough the powers of A and B separately, and check if the number can be rooted.
This means an additional check if the rounded-down value of the double is the same as the double. (Meaning the pow 1/3, 1/4 yields an integer result.)
public static void main(String[] args) {
for (int a = 2; a <= 100; a++) {
for (int b = 2; b <= 100; b++) {
BigInteger newa = BigInteger.valueOf(a);
BigInteger newb = BigInteger.valueOf(b);
BigInteger thegcd = newa.gcd(newb);
if (thegcd.compareTo(BigInteger.ONE) == 0) {
double highest = Math.max(a, b);
double powlim = (Math.log10(highest) / Math.log10(2.0));
for (double powerA = 3; powerA <= powlim; powerA++) {
double roota = Math.pow(a, 1.0 / powerA);
for (double powerB = 3; powerB <= powlim; powerB++) {
double rootb = Math.pow(b, 1.0 / powerB);
if (rootb == Math.floor(rootb) && roota == Math.floor(roota)) {
if ((Math.round(Math.pow(roota, powerA)) == a) && (Math.round(Math.pow(rootb, powerB)) == b)) {
if (a < b) {
System.out.println(a + "\t" + b);
}
}
}
}
}
}
}
}
}

Understanding the strictMath java library

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 ...

Java- Get decimal at position n

What is the best way to get the decimal at position n from a float (by cutting out everything from the number except that decimal)?
It should work like this:
getDecimal(3.654987, 4) => returns 0.0009
getDecimal(3.654987, 2) => returns 0.05
Float f = new Float("0.123456789");
System.out.println(f.toString().charAt(5));
Prints 4. Try in this direction.
This should work for you:
public static double getDecimal(double num, int n) {
return ((int) (num * Math.pow(10, (double) n)) % 10) * Math.pow(10, (double) -n);
}
Assuming the position will be always a positive integer(> 0):
float input = 3.654987f;
int pos = 4;
String op = String.valueOf(input).replaceAll("\\d*\\.\\d{"+(pos-1)+"}(\\d)\\d+",
"0." + new String(new char[pos-1]).replace("\0", "0") + "$1");
System.out.println(op);

Rounding up a number to nearest multiple of 5

Does anyone know how to round up a number to its nearest multiple of 5? I found an algorithm to round it to the nearest multiple of 10 but I can't find this one.
This does it for ten.
double number = Math.round((len + 5)/ 10.0) * 10.0;
To round to the nearest of any value:
int round(double value, int nearest) {
return (int) Math.round(value / nearest) * nearest;
}
You can also replace Math.round() with either Math.floor() or Math.ceil() to make it always round down or always round up.
int roundUp(int n) {
return (n + 4) / 5 * 5;
}
Note - YankeeWhiskey's answer is rounding to the closest multiple, this is rounding up. Needs a modification if you need it to work for negative numbers. Note that integer division followed by integer multiplication of the same number is the way to round down.
I think I have it, thanks to Amir
double round( double num, int multipleOf) {
return Math.floor((num + multipleOf/2) / multipleOf) * multipleOf;
}
Here's the code I ran
class Round {
public static void main(String[] args){
System.out.println("3.5 round to 5: " + Round.round(3.5, 5));
System.out.println("12 round to 6: " + Round.round(12, 6));
System.out.println("11 round to 7: "+ Round.round(11, 7));
System.out.println("5 round to 2: " + Round.round(5, 2));
System.out.println("6.2 round to 2: " + Round.round(6.2, 2));
}
public static double round(double num, int multipleOf) {
return Math.floor((num + (double)multipleOf / 2) / multipleOf) * multipleOf;
}
}
And here's the output
3.5 round to 5: 5.0
12 round to 6: 12.0
11 round to 7: 14.0
5 round to 2: 6.0
6.2 round to 2: 6.0
int roundUp(int num) {
return (int) (Math.ceil(num / 5d) * 5);
}
int roundUp(int num) {
return ((num / 5) + (num % 5 > 0 ? 1 : 0)) * 5;
}
int round(int num) {
int temp = num%5;
if (temp<3)
return num-temp;
else
return num+5-temp;
}
int getNextMultiple(int num , int multipleOf) {
int nextDiff = multipleOf - (num % multipleOf);
int total = num + nextDiff;
return total;
}
int roundToNearestMultiple(int num, int multipleOf){
int floorNearest = ((int) Math.floor(num * 1.0/multipleOf)) * multipleOf;
int ceilNearest = ((int) Math.ceil(num * 1.0/multipleOf)) * multipleOf;
int floorNearestDiff = Math.abs(floorNearest - num);
int ceilNearestDiff = Math.abs(ceilNearest - num);
if(floorNearestDiff <= ceilNearestDiff) {
return floorNearest;
} else {
return ceilNearest;
}
}
This Kotlin function rounds a given value 'x' to the closest multiple of 'n'
fun roundXN(x: Long, n: Long): Long {
require(n > 0) { "n(${n}) is not greater than 0."}
return if (x >= 0)
((x + (n / 2.0)) / n).toLong() * n
else
((x - (n / 2.0)) / n).toLong() * n
}
fun main() {
println(roundXN(121,4))
}
Output: 120
Kotlin with extension function.
Possible run on play.kotlinlang.org
import kotlin.math.roundToLong
fun Float.roundTo(roundToNearest: Float): Float = (this / roundToNearest).roundToLong() * roundToNearest
fun main() {
println(1.02F.roundTo(1F)) // 1.0
println(1.9F.roundTo(1F)) // 2.0
println(1.5F.roundTo(1F)) // 2.0
println(1.02F.roundTo(0.5F)) // 1.0
println(1.19F.roundTo(0.5F)) // 1.0
println(1.6F.roundTo(0.5F)) // 1.5
println(1.02F.roundTo(0.1F)) // 1.0
println(1.19F.roundTo(0.1F)) // 1.2
println(1.51F.roundTo(0.1F)) // 1.5
}
Possible to use floor/ceil like this:
fun Float.floorTo(roundToNearest: Float): Float = floor(this / roundToNearest) * roundToNearest
Some people are saying something like
int n = [some number]
int rounded = (n + 5) / 5 * 5;
This will round, say, 5 to 10, as well as 6, 7, 8, and 9 (all to 10). You don't want 5 to round to 10 though. When dealing with just integers, you want to instead add 4 to n instead of 5. So take that code and replace the 5 with a 4:
int n = [some number]
int rounded = (n + 4) / 5 * 5;
Of course, when dealing with doubles, just put something like 4.99999, or if you want to account for all cases (if you might be dealing with even more precise doubles), add a condition statement:
int n = [some number]
int rounded = n % 5 == 0 ? n : (n + 4) / 5 * 5;
Another Method or logic to rounding up a number to nearest multiple of 5
double num = 18.0;
if (num % 5 == 0)
System.out.println("No need to roundoff");
else if (num % 5 < 2.5)
num = num - num % 5;
else
num = num + (5 - num % 5);
System.out.println("Rounding up to nearest 5------" + num);
output :
Rounding up to nearest 5------20.0
I've created a method that can convert a number to the nearest that will be passed in, maybe it will help to someone, because i saw a lot of ways here and it did not worked for me but this one did:
/**
* The method is rounding a number per the number and the nearest that will be passed in.
* If the nearest is 5 - (63->65) | 10 - (124->120).
* #param num - The number to round
* #param nearest - The nearest number to round to (If the nearest is 5 -> (0 - 2.49 will round down) || (2.5-4.99 will round up))
* #return Double - The rounded number
*/
private Double round (double num, int nearest) {
if (num % nearest >= nearest / 2) {
num = num + ((num % nearest - nearest) * -1);
} else if (num % nearest < nearest / 2) {
num = num - (num % nearest);
}
return num;
}
In case you only need to round whole numbers you can use this function:
public static long roundTo(long value, long roundTo) {
if (roundTo <= 0) {
throw new IllegalArgumentException("Parameter 'roundTo' must be larger than 0");
}
long remainder = value % roundTo;
if (Math.abs(remainder) < (roundTo / 2d)) {
return value - remainder;
} else {
if (value > 0) {
return value + (roundTo - Math.abs(remainder));
} else {
return value - (roundTo - Math.abs(remainder));
}
}
}
The advantage is that it uses integer arithmetics and works even for large long numbers where the floating point division will cause you problems.
int roundUp(int n, int multipleOf)
{
int a = (n / multipleOf) * multipleOf;
int b = a + multipleOf;
return (n - a > b - n)? b : a;
}
source: https://www.geeksforgeeks.org/round-the-given-number-to-nearest-multiple-of-10/
Praveen Kumars question elsewhere in this Thread
"Why are we adding 4 to the number?"
is very relevant. And it is why I prefer to code it like this:
int roundUpToMultipleOf5(final int n) {
return (n + 5 - 1) / 5 * 5;
}
or, passing the value as an argument:
int roundUpToMultiple(final int n, final int multipleOf) {
return (n + multipleOf - 1) / multipleOf * multipleOf;
}
By adding 1 less than the multiple you're looking for, you've added just enough to make sure that a value of n which is an exact multiple will not round up, and any value of n which is not an exact multiple will be rounded up to the next multiple.
Recursive:
public static int round(int n){
return (n%5==0) ? n : round(++n);
}
Just pass your number to this function as a double, it will return you rounding the decimal value up to the nearest value of 5;
if 4.25, Output 4.25
if 4.20, Output 4.20
if 4.24, Output 4.20
if 4.26, Output 4.30
if you want to round upto 2 decimal places,then use
DecimalFormat df = new DecimalFormat("#.##");
roundToMultipleOfFive(Double.valueOf(df.format(number)));
if up to 3 places, new DecimalFormat("#.###")
if up to n places, new DecimalFormat("#.nTimes #")
public double roundToMultipleOfFive(double x)
{
x=input.nextDouble();
String str=String.valueOf(x);
int pos=0;
for(int i=0;i<str.length();i++)
{
if(str.charAt(i)=='.')
{
pos=i;
break;
}
}
int after=Integer.parseInt(str.substring(pos+1,str.length()));
int Q=after/5;
int R =after%5;
if((Q%2)==0)
{
after=after-R;
}
else
{
after=after+(5-R);
}
return Double.parseDouble(str.substring(0,pos+1).concat(String.valueOf(after))));
}
Here's what I use for rounding to multiples of a number:
private int roundToMultipleOf(int current, int multipleOf, Direction direction){
if (current % multipleOf == 0){
return ((current / multipleOf) + (direction == Direction.UP ? 1 : -1)) * multipleOf;
}
return (direction == Direction.UP ? (int) Math.ceil((double) current / multipleOf) : (direction == Direction.DOWN ? (int) Math.floor((double) current / multipleOf) : current)) * multipleOf;
}
The variable current is the number you're rounding, multipleOf is whatever you're wanting a multiple of (i.e. round to nearest 20, nearest 10, etc), and direction is an enum I made to either round up or down.
Good luck!
Round a given number to the nearest multiple of 5.
public static int round(int n)
while (n % 5 != 0) n++;
return n;
}
You can use this method Math.round(38/5) * 5 to get multiple of 5
It can be replace with Math.ceil or Math.floor based on how you want to round off the number
Use this method to get nearest multiple of 5.
private int giveNearestMul5(int givenValue){
int roundedNum = 0;
int prevMul5, nextMul5;
prevMul5 = givenValue - givenValue%5;
nextMul5 = prevMul5 + 5;
if ((givenValue%5!=0)){
if ( (givenValue-prevMul5) < (nextMul5-givenValue) ){
roundedNum = prevMul5;
} else {
roundedNum = nextMul5;
}
} else{
roundedNum = givenValue;
}
return roundedNum;
}
if (n % 5 == 1){
n -= 1;
} else if (n % 5 == 2) {
n -= 2;
} else if (n % 5 == 3) {
n += 2;
} else if (n % 5 == 4) {
n += 1;
}
CODE:
public class MyMath
{
public static void main(String[] args) {
runTests();
}
public static double myFloor(double num, double multipleOf) {
return ( Math.floor(num / multipleOf) * multipleOf );
}
public static double myCeil (double num, double multipleOf) {
return ( Math.ceil (num / multipleOf) * multipleOf );
}
private static void runTests() {
System.out.println("myFloor (57.3, 0.1) : " + myFloor(57.3, 0.1));
System.out.println("myCeil (57.3, 0.1) : " + myCeil (57.3, 0.1));
System.out.println("");
System.out.println("myFloor (57.3, 1.0) : " + myFloor(57.3, 1.0));
System.out.println("myCeil (57.3, 1.0) : " + myCeil (57.3, 1.0));
System.out.println("");
System.out.println("myFloor (57.3, 5.0) : " + myFloor(57.3, 5.0));
System.out.println("myCeil (57.3, 5.0) : " + myCeil (57.3, 5.0));
System.out.println("");
System.out.println("myFloor (57.3, 10.0) : " + myFloor(57.3,10.0));
System.out.println("myCeil (57.3, 10.0) : " + myCeil (57.3,10.0));
}
}
OUTPUT:There is a bug in the myCeil for multiples of 0.1 too ... no idea why.
myFloor (57.3, 0.1) : 57.2
myCeil (57.3, 0.1) : 57.300000000000004
myFloor (57.3, 1.0) : 57.0
myCeil (57.3, 1.0) : 58.0
myFloor (57.3, 5.0) : 55.0
myCeil (57.3, 5.0) : 60.0
myFloor (57.3, 10.0) : 50.0
myCeil (57.3, 10.0) : 60.0

Newton's method with specified digits of precision

I'm trying to write a function in Java that calculates the n-th root of a number. I'm using Newton's method for this. However, the user should be able to specify how many digits of precision they want. This is the part with which I'm having trouble, as my answer is often not entirely correct. The relevant code is here: http://pastebin.com/d3rdpLW8. How could I fix this code so that it always gives the answer to at least p digits of precision? (without doing more work than is necessary)
import java.util.Random;
public final class Compute {
private Compute() {
}
public static void main(String[] args) {
Random rand = new Random(1230);
for (int i = 0; i < 500000; i++) {
double k = rand.nextDouble()/100;
int n = (int)(rand.nextDouble() * 20) + 1;
int p = (int)(rand.nextDouble() * 10) + 1;
double math = n == 0 ? 1d : Math.pow(k, 1d / n);
double compute = Compute.root(n, k, p);
if(!String.format("%."+p+"f", math).equals(String.format("%."+p+"f", compute))) {
System.out.println(String.format("%."+p+"f", math));
System.out.println(String.format("%."+p+"f", compute));
System.out.println(math + " " + compute + " " + p);
}
}
}
/**
* Returns the n-th root of a positive double k, accurate to p decimal
* digits.
*
* #param n
* the degree of the root.
* #param k
* the number to be rooted.
* #param p
* the decimal digit precision.
* #return the n-th root of k
*/
public static double root(int n, double k, int p) {
double epsilon = pow(0.1, p+2);
double approx = estimate_root(n, k);
double approx_prev;
do {
approx_prev = approx;
// f(x) / f'(x) = (x^n - k) / (n * x^(n-1)) = (x - k/x^(n-1)) / n
approx -= (approx - k / pow(approx, n-1)) / n;
} while (abs(approx - approx_prev) > epsilon);
return approx;
}
private static double pow(double x, int y) {
if (y == 0)
return 1d;
if (y == 1)
return x;
double k = pow(x * x, y >> 1);
return (y & 1) == 0 ? k : k * x;
}
private static double abs(double x) {
return Double.longBitsToDouble((Double.doubleToLongBits(x) << 1) >>> 1);
}
private static double estimate_root(int n, double k) {
// Extract the exponent from k.
long exp = (Double.doubleToLongBits(k) & 0x7ff0000000000000L);
// Format the exponent properly.
int D = (int) ((exp >> 52) - 1023);
// Calculate and return 2^(D/n).
return Double.longBitsToDouble((D / n + 1023L) << 52);
}
}
Just iterate until the update is less than say, 0.0001, if you want a precision of 4 decimals.
That is, set your epsilon to Math.pow(10, -n) if you want n digits of precision.
Let's recall what the error analysis of Newton's method says. Basically, it gives us an error for the nth iteration as a function of the error of the n-1 th iteration.
So, how can we tell if the error is less than k? We can't, unless we know the error at e(0). And if we knew the error at e(0), we would just use that to find the correct answer.
What you can do is say "e(0) <= m". You can then find n such that e(n) <= k for your desired k. However, this requires knowing the maximal value of f'' in your radius, which is (in general) just as hard a problem as finding the x intercept.
What you're checking is if the error changes by less than k, which is a perfectly acceptable way to do it. But it's not checking if the error is less than k. As Axel and others have noted, there are many other root-approximation algorithms, some of which will yield easier error analysis, and if you really want this, you should use one of those.
You have a bug in your code. Your pow() method's last line should read
return (y & 1) == 1 ? k : k * x;
rather than
return (y & 1) == 0 ? k : k * x;

Categories