i'm trying to convert decimals into fractions. my program works just fine for other numbers. however when trying to find the numerator and denominator for 1.0923059908040425e-33,
java gives 1/9
where as python gives 0.
this is my code for java:
class Rational {
public static void main(String[] args) {
println(getDenominator(convertDecimalToFraction(1.0923059908040425e-33)));
}
public static int getNumerator(String fraction) {
return Integer.valueOf(fraction.substring(0, fraction.indexOf(".")));
}
public static int getDenominator(String fraction) {
fraction = fraction.substring(fraction.indexOf("/") + 1);
return Integer.valueOf(fraction.substring(0, fraction.indexOf(".")));
}
static private String convertDecimalToFraction(double x){
if (x < 0){
return "-" + convertDecimalToFraction(-x);
}
double tolerance = 1.0E-6;
double h1=1; double h2=0;
double k1=0; double k2=1;
double b = x;
do {
double a = Math.floor(b);
double aux = h1; h1 = a*h1+h2; h2 = aux;
aux = k1; k1 = a*k1+k2; k2 = aux;
b = 1/(b-a);
} while (Math.abs(x-h1/k1) > x*tolerance);
return h1+"/"+k1;
}
}
and this is python:
print(fractions.Fraction(1.0923059908040425e-33).limit_denominator())
i think there's problem in my java code because i'm expecting 0 as correct output, but there is built-in library available for Fractions, and i don't want to use any third-party libraries.
java code works on mostly all inputs. only problem with this one input. please point me error if any.
i would really appreciate if you can provide me with a method or logic that can solve this problem
print(fractions.Fraction(1.0923059908040425e-33)) gives 6385627976105849/5846006549323611672814739330865132078623730171904
after adding limit_denominator, it becomes 0.
i don't know what is going on here..
Well a bit a debugging would immediately show what happens. convertDecimalToFraction returns "1.0/9.15494383825455E32" which is not stupid, but getDenominator just ignores the E32. You should mimic the limit_denominator from Python and say that if x<tolerance then the returned value shall be "0./1.":
static private String convertDecimalToFraction(double x){
if (x < 0){
return "-" + convertDecimalToFraction(-x);
}
double tolerance = 1.0E-6;
if (x < tolerance) {
return "0./1.";
}
double h1=1; double h2=0;
double k1=0; double k2=1;
double b = x;
do {
double a = Math.floor(b);
double aux = h1; h1 = a*h1+h2; h2 = aux;
aux = k1; k1 = a*k1+k2; k2 = aux;
b = 1/(b-a);
} while (Math.abs(x-h1/k1) > x*tolerance);
return h1+"/"+k1;
}
Related
What am I doing wrong?
The median is always -0.5 result or 0.5, if ((m) + (m+1))/2;
public static double mediana(List<Double> liczby ){
Collections.sort(liczby);
int n = liczby.size()/2;
double m;
m = get(n);
if (liczby.size() % 2 == 0){
return ((m) + (m-1))/2;
}
else {
return m;
}
}
In your code, the problem is in this line.
return ((m) + (m-1))/2;
It should return the average of nth number and (n-1)th number as n = (size of the list)/2. You can try this.
public static double mediana(List<Double> liczby ){
Collections.sort(liczby);
int n = liczby.size()/2;
double m;
if (liczby.size() % 2 == 0)
m = (liczby.get(n) + liczby.get(n-1))/2;
else
m = liczby.get(n);
return m;
}
I believe the problem with it is the line return ((m) + (m-1))/2; You forget to retrieve the input of the next element in the list. Try:
l = get(n+1);
return (m + l)/2;
instead of:
return ((m) + (m-1))/2;
You need to be retrieving the n and n-1-th elements. You are currently subtracting 1 from the n-th value, which is not meaningful:
return (get(n) + get(n-1)) / 2;
I faced the same problem yesterday and I wrote a solution similar to sifho's one.
My method---implemented using Java generics---calculates the median value on every collection of Numbers. You can use the method with collections of Doubles, Integers, Floats and returns a double. Please consider that my method creates another collection in order to not alter the original one.
I provide also a test, have fun. ;-)
public static <T extends Number & Comparable<T>> double median(Collection<T> numbers){
if(numbers.isEmpty()){
throw new IllegalArgumentException("Cannot compute median on empty array of numbers");
}
List<T> numbersList = new ArrayList<>(numbers);
Collections.sort(numbersList);
int middle = numbersList.size()/2;
if(numbersList.size() % 2 == 0){
return 0.5 * (numbersList.get(middle).doubleValue() + numbersList.get(middle-1).doubleValue());
} else {
return numbersList.get(middle).doubleValue();
}
}
JUnit test code snippet:
/**
* Test of median method, of class Utils.
*/
#Test
public void testMedian() {
System.out.println("median");
Double expResult = 3.0;
Double result = Utils.median(Arrays.asList(3.0,2.0,1.0,9.0,13.0));
assertEquals(expResult, result);
expResult = 3.5;
result = Utils.median(Arrays.asList(3.0,2.0,1.0,9.0,4.0,13.0));
assertEquals(expResult, result);
}
Usage example (consider the class name is Utils):
List<Integer> intValues = ... //omitted init
Set<Float> floatValues = ... //omitted init
.....
double intListMedian = Utils.median(intValues);
double floatSetMedian = Utils.median(floatValues);
I do not know how to look method get(n).
It generates automatically.
The method can not return to zero.
private static double get(int n) {
// TODO Auto-generated method stub
return 0;
}
Is there a proper way for converting a double value to a BigInteger value and later back? In the best case without loosing data. The problem is, that I don't know how many decimal places the double values have. But I need this conversion for an Algorithm which only works with non decimal values. After the Algorithm finishes I have to convert it back.
An easy example what I need: for example the sum of 2 double values but the "sum" function works only with BigInteger.
You can do it in 5 steps:
double d1 = 0.1; //your original double
BigDecimal bd1 = new BigDecimal(d1); //convert to BigDecimal
BigInteger bi = bd1.unscaledValue(); //convert to BigInteger
//here do your stuff with the BigInteger
BigDecimal bd2 = new BigDecimal(bi, bd1.scale()); //back to BigDecimal, applying scale
double d2 = bd2.doubleValue(); //convert to double
Full example applied to a sum method
Output:
0.1 + 0.1 = 0.2
0.1 + 10.1 = 10.2
0.1245 + 17.0 = 17.1245
Code:
public static void main(String[] args) {
test(0.1, 0.1);
test(0.1, 10.1);
test(0.1245, 17);
}
private static void test(double d1, double d2) {
System.out.println(d1 + " + " + d2 + " = " + sum(d1, d2));
}
private static double sum(double d1, double d2) {
BigDecimal bd1 = new BigDecimal(d1);
BigDecimal bd2 = new BigDecimal(d2);
int shift = Integer.max(bd1.scale(), bd2.scale());
BigInteger bi1 = bd1.scaleByPowerOfTen(shift).toBigInteger();
BigInteger bi2 = bd2.scaleByPowerOfTen(shift).toBigInteger();
BigInteger sum = sum(bi1, bi2);
return new BigDecimal(sum, shift).doubleValue();
}
private static BigInteger sum(BigInteger i1, BigInteger i2) {
return i1.add(i2);
}
This program is based on the BigDecimal-and-scale idea, as in assylias's answer, but modified to unconditionally use the maximum possible required scale. This allows the same scale to be used across a stream of numbers, without seeing all the numbers before processing any of them. The cost is that it will usually return unnecessarily large BigInteger values.
The scale factor, "1e1074", is based on the observation that all finite double numbers are integer multiples of Double.MIN_VALUE, which has 1074 decimal digits after the decimal point. No double can have more decimal digits after the decimal point.
import java.math.BigDecimal;
import java.math.BigInteger;
public class Test {
public static void main(String[] args) {
testit(Double.MIN_VALUE);
testit(Double.MAX_VALUE);
testit(0);
testit(1.0);
testit(Math.E);
testit(Math.PI);
}
private static void testit(double d) {
double roundTrip = scaledIntegerToDouble(doubleToScaledInteger(d));
if (d != roundTrip) {
System.out.println("ERROR: " + d + " " + roundTrip);
}
}
public static final BigDecimal scale = new BigDecimal("1e1074");
public static BigInteger doubleToScaledInteger(double d) {
BigDecimal bd = new BigDecimal(d).multiply(scale);
return bd.toBigIntegerExact();
}
public static double scaledIntegerToDouble(BigInteger bi) {
BigDecimal bd = new BigDecimal(bi).divide(scale);
return bd.doubleValue();
}
}
package test;
import java.math.*;
public class HelloWorld{
public static BigInteger sumBigInteger(BigInteger n1,BigInteger n2){
return n1.add(n2);
}
public static double sumDouble(double n1,double n2){
int scale=1;
int max = Math.max(((""+n1).split("\\."))[1].length(), ((""+n2).split("\\."))[1].length());
for (int i=0;i<max;i++) scale*=10;
BigInteger nbr1 = new BigDecimal(n1*scale).toBigInteger();
BigInteger nbr2 = new BigDecimal(n2*scale).toBigInteger();
return (sumBigInteger(nbr1,nbr2).doubleValue() / scale);
}
public static void main(String []args){
double n1=117.22 , n2=56.945;
System.out.println(n1+" + "+n2+" = "+sumDouble(n1,n2));
}
}
Output:
117.22 + 56.945 = 174.165
I have a method that is converting a decimal (double value) into a fraction and putting the numerator and denominator values into an int[] of size 2.
Testing it works out fine for most values except when I hit 0.0001. Then the return value is 1.0/1.0.
The method:
private static int[] toFractionPos(double x){
String[] parts = Double.toString(x).split("\\.");
double den = Math.pow(10, parts[1].length()); //denominator
double num = Double.parseDouble(parts[0]) * den + Double.parseDouble(parts[1]); //numerator
return reduceFraction((int)num, (int)den);
}
reduceFraction() method:
public static int[] reduceFraction(int num, int den){
int gcf = GCF(num, den); //greatest common factor
int[] rf = {num/gcf, den/gcf};
return rf;
}
Thanks!
The algorithm seems fine. However, using double is not suitable for this kind of problem, because precision decreases as the scale grows.
You should use BigDecimal and BigInteger instead. I've roughly modified your example so that it works with them, but I haven't taken care of details, i.e. parsing the String shouldn't be necessary since scale can be retrieved from a BigDecimal with a getter, you can configure different rounding modes, etc:
import java.math.BigDecimal;
import java.math.BigInteger;
public class Sample {
static int[] toFractionPos(BigDecimal x) {
String[] parts = x.toString().split("\\.");
BigDecimal den = BigDecimal.TEN.pow(parts[1].length()); // denominator
BigDecimal num = (new BigDecimal(parts[0]).multiply(den)).add(new BigDecimal(parts[1])); // numerator
return reduceFraction(num.intValue(), den.intValue());
}
static int[] reduceFraction(int num, int den) {
int gcd = BigInteger.valueOf(num).gcd(BigInteger.valueOf(den)).intValue(); // greatest
// common
// divisor
int[] rf = { num / gcd, den / gcd };
return rf;
}
public static void main(String[] args) {
int[] fraction = toFractionPos(new BigDecimal("0.0001"));
System.out.println(fraction[0] + "/" + fraction[1]); // 1/10000
}
}
Note: optimizations left as an excercise ;)
You shouldn't work with doubles as you are losing precision and this can lead to serious errors. But in the case of 1.0001 the problem is that:
Double.toString(1.0001) == "1.0E-4"
Then you try to parse "0E-4" and you get 0 instead of 1. You could do the following if you expect at most 10 decimal points:
DecimalFormat df = new DecimalFormat("0",
DecimalFormatSymbols.getInstance(Locale.ENGLISH));
df.setMaximumFractionDigits(10);
String[] parts = df.format(x).split("\\.");
How about this?
private static int[] toFractionPos(double x){
int den = (int)Math.pow(10,(int)Math.log10(Integer.MAX_VALUE));
int num = (int)(x*den);
return reduceFraction(num, den);//this came from your code
}
I think this will work,
public int[] Fraction(double n) {
BigDecimal p = BigDecimal.ONE;
BigDecimal dn = BigDecimal.valueOf(n);
while(true){
dn = dn.multiply(p);
if( dn.compareTo(new BigDecimal(dn.toBigInteger()))==0 )
break;
else
p = p.multiply(BigDecimal.TEN);
}
BigInteger num=dn.toBigInteger(), den=p.toBigInteger(), g=num.gcd(den);
num = num.divide(g);
den = den.divide(g);
int[] res = new int[2];
res[0] = num.intValue();
res[0] = den.intValue();
return res;
}
I want to calculate factorial my code at present is this:
else if(btn.getText().equals("x!"))
{
double LeftVal = Double.parseDouble(currentInput);
double result = Double.NaN;
if(currentInputLen > 0 && LeftVal >0)
{
result = Factorial(LeftVal);
}
resultText.setText(result+"");
}
code to calculate factorial is this:
private double Factorial(double input)
{
double output=input;
for(int i=(int) (input-1);i>0;i--)
{
output*=i;
}
return output;
}
I imported java.math.*; and changed my code to this:
else if(btn.getText().equals("x!"))
{
BigInteger LeftVal = BigInteger(currentInput);
BigInteger result = 0;
if(currentInputLen > 0 && LeftVal >0)
{
result = Factorial(LeftVal);
}
resultText.setText(result+"");
}
and factorial method to this
private BigInteger Factorial(BigInteger input)
{
BIgInteger output=input;
for(int i=(int) (input-1);i>0;i--)
{
output*=i;
}
return output;
}
I saw on android developer site that BigInteger(string) will convert that string to big integer but that does not work and shows error also there were errors on using regular mathematical errors.
The reason i want to use big integer is because if i calculate 12! using double it shows answer in scientific form with e raised to power something i want exact answer.
For your factorial method using BigInteger you could use:
private BigInteger factorial(BigInteger input) {
BigInteger output = input;
for (BigInteger i = input.subtract(BigInteger.ONE); i.compareTo(BigInteger.ZERO) > 0; i = i.subtract(BigInteger.ONE)) {
output = output.multiply(i);
}
return output;
}
I created a method:
public double Calculouno(double x1,double x2,double y1,double y2)
{
double ecuacion1;
ecuacion1= (x2-x1)+(y2-y1);
ecuacion1= Math.sqrt(ecuacion1);
return ecuacion1;
}
When my program tries to calculate ecuacion1 using mathematical functions such as pow and sqrt (at least that´s what I suspect), it just stops working without a compiler warning and says "Build succesful". Help please.
When i reach this part (method), the compiler says "Build succesful" and it just ends. My program works great until this part.
This is the entire source code.
import java.util.Scanner;
import java.lang.Math;
public class Ejercicio12
{
public static void main(String args[])
{
double[] x= new double[3];
double[] y= new double[3];
double a,b,c;
int con=0, con2=0;
double[] angulo= new double[3];
Scanner entrada = new Scanner(System.in);
Calculos cal= new Calculos();
for(con=0;con<3;con++)
{
System.out.println("Ingrese un valor x para el punto "+(con+1)+": ");
x[con]= entrada.nextDouble();
System.out.println("Ingrese un valor y para el punto "+(con+1)+": ");
y[con]= entrada.nextDouble();
}
a= cal.Calculouno(x[0],x[1],y[0],y[1]);
b= cal.Calculouno(x[1],x[2],y[1],y[2]);
c= cal.Calculouno(x[2],x[0],y[2],y[0]);
angulo[0]= cal.Angulo(a,b,c);
angulo[1]= cal.Angulo(c,a,b);
angulo[2]= cal.Angulo(b,a,c);
if(angulo[0]>90||angulo[1]>90||angulo[2]>90)
{
System.out.println("El triangulo es obtusangulo");
}
else
{
if(angulo[0]==90||angulo[1]==90||angulo[2]==90)
{
System.out.println("El triangulo es rectangulo");
}
else
{
if(angulo[0]<90&&angulo[1]<90&&angulo[2]<90)
{
System.out.println("El triangulo es acutangulo");
}
}
}
}
}
import static java.lang.Math.sqrt;
import static java.lang.Math.pow;
import static java.lang.Math.acos;
public class Calculos
{
public double Calculouno(double x1,double x2,double y1,double y2)
{
double ecuacion1;
double dx= (x2-x1);
double dy= (y2-y1);
return Math.sqrt(dy+dx);
}
public double Angulo(double a1,double b1, double c1)
{
double ecuacion2;
double a11 = pow(a1,2);
double b11 = pow(b1,2);
double c11 = pow(c1,1);
double xx=(b11+c11-a11);
double zz=(2*b1*c1);
return Math.acos(xx/zz);
}
}
There is nothing in the code in your snippet that will (directly) cause the program to "stop without warning".
There are no syntax errors (etcetera) that would cause a build to fail. (And that matches what you report.)
Giving "bad" input to Math.sqrt won't cause it to stop, or even throw an exception. The javadoc says: "[Returns] the positive square root of a. If the argument is NaN or less than zero, the result is NaN." i.e. bad input will give you a NaN value.
Bad input wouldn't cause the arithmetic before the sqrt call to throw exceptions. The JLS says (for the floating point + and - operators) "[i]f either operand is NaN, the result is NaN."
So the immediate cause of your application's stopping must be somewhere else in your application.
I expect that what is happening is that some other part of your code is throwing an exception when it gets an unexpected result from this method (maybe a NaN) ... and your application is squashing the exception.
I understand the problem now.
What is happening is that the arithmetic and/or calls to sqrt and pow >>are<< generating NaN values. When you test a NaN value using any of the relational operators, the result of the expression is always false. So that means that your code that none of the println calls is made.
Your code is not actually stopping. Rather it is completing normally without producing any output.
And the underlying reason that the calculations are producing NaN values is ... as #duffymo has pointed out ... that you have implemented the geometric formulae incorrectly.
For the record, NaN values have peculiar behaviour when they are used in a relation expressions. For instance:
double x = 0.0 / 0.0; // generate a NaN
System.out.println(0.0 == x);
System.out.println(0.0 != x);
System.out.println(0.0 < x);
System.out.println(0.0 > x);
System.out.println(x == x);
System.out.println(x != x);
System.out.println(x < x);
System.out.println(x > x);
All will of the above will print "false". Yes, all of them!
The only way to test for a NaN is to use Double.isNaN(double) or Float.isNaN(float).
Here are two links that I believe describe the problem you want to solve pretty well:
http://mathworld.wolfram.com/AcuteTriangle.html
and
http://mathworld.wolfram.com/ObtuseTriangle.html
Here's how I might write it. I didn't test it exhaustively:
package cruft;
/**
* Junk description here
* #author Michael
* #link
* #since 9/8/12 10:19 PM
*/
public class Triangle {
private final Point p1;
private final Point p2;
private final Point p3;
public static void main(String args[]) {
if (args.length > 5) {
Point p1 = new Point(Double.valueOf(args[0]), Double.valueOf(args[1]));
Point p2 = new Point(Double.valueOf(args[2]), Double.valueOf(args[3]));
Point p3 = new Point(Double.valueOf(args[4]), Double.valueOf(args[5]));
Triangle triangle = new Triangle(p1, p2, p3);
double angle = triangle.calculateAngle();
System.out.println(triangle);
if (angle > 0.0) {
System.out.println("obtuse");
} else if (angle < 0.0) {
System.out.println("acute");
} else {
System.out.println("right triangle");
}
} else {
System.out.println("Usage: Triangle x1 y1 x2 y2 x3 y3");
}
}
public Triangle(Point p1, Point p2, Point p3) {
this.p1 = p1;
this.p2 = p2;
this.p3 = p3;
}
public double calculateAngle(){
double a = Point.distance(this.p1, this.p2);
double b = Point.distance(this.p2, this.p3);
double c = Point.distance(this.p3, this.p1);
return Math.acos(a*a + b*b - c*c)/2.0/a/b;
}
#Override
public String toString() {
final StringBuilder sb = new StringBuilder();
sb.append("Triangle");
sb.append("{p1=").append(p1);
sb.append(", p2=").append(p2);
sb.append(", p3=").append(p3);
sb.append('}');
return sb.toString();
}
}
class Point {
public final double x;
public final double y;
public Point(double x, double y) {
this.x = x;
this.y = y;
}
public static double distance(Point q1, Point q2) {
double dx = Math.abs(q1.x-q2.x);
double dy = Math.abs(q1.y-q2.y);
if (dx > dy) {
double r = dy/dx;
return dx*Math.sqrt(1.0+r*r);
} else {
double r = dx/dy;
return dy*Math.sqrt(1.0+r*r);
}
}
#Override
public String toString() {
final StringBuilder sb = new StringBuilder();
sb.append('(').append(x);
sb.append(',').append(y);
sb.append(')');
return sb.toString();
}
}