Error in calculating PI in Java with BigDecimal - java

I have to calculate PI to a certain number of decimals (given in variable zecimale), using the Leibniz formula for calculating PI. I don't know why, but not a single addition or subtraction on that BigDecimal isn't modifying the value of PI.
Why is this?
int zecimale = 0;
if (args.length > 0) {
try {
zecimale = Integer.parseInt(args[0]);
} catch (NumberFormatException e) {
System.err.println("Argument" + " must be an integer");
System.exit(1);
}
}
long start = System.nanoTime();
double numitor = 1;
BigDecimal numitor1 = new BigDecimal(1/numitor);
BigDecimal pi = new BigDecimal(1);
for(int x = 0; pi.scale() <= zecimale; x++)
{
numitor1 = new BigDecimal(1 / numitor);
if(x % 2 == 0)
{
pi.add(numitor1);
}
else
{
pi.subtract(numitor1);
}
BigDecimal doi = new BigDecimal(2);
numitor = numitor + 2;
System.out.println(x);
System.out.println(pi);
}
BigDecimal patru;
patru = new BigDecimal(4);
pi.multiply(patru);

BigDecimal is immutable so the is no way to change it's value. (In the same way String does) This is why all the methods would operate on a BigDecimal return a new BigDecimal as the result
e.g.
pi = pi.add(numitor1);
The second problem is you are using a double in your calculation, defeating the whole point of using a BigDecimal.
The expression pi.scale() should be ~53 after the first iteration and won't get much higher the way ti is written. scale only tells you how many decimal places there are after the dot, not the accuracy of the solution.
You will get better performance if you calculate two expressions in a single loop.
The last problem you have is that each digit takes 10x longer to evaluate, calculating mroe than 15 digits (more than the precision you can get with double) it will take years to complete.

Related

Calculating a BigDecimal results in inaccurate answer

So I just wanted to screw around to see if I can make it so I can calculate E, but instead have it so I can have dynamic degrees of precision. While I did technically accomplish it, no matter what int i put in for the variable PRECISION, the last few numbers are always different from what the actual value of E is suppose to be. I'm not entirely sure why, but help would be appreciated.
import java.math.BigDecimal; //To use for calculating E
public class ComputeE {
public static double calcDenominator(int n)
{
double denominator = 1.0; //Start the BigInt with 1
for(int i = 1; i < n; i++) // Run n-1 amount of times
{
denominator = denominator * i; // Multiply BigInteger by the BigInteger obtained with the int value i
}
return denominator;
}
public static void main(String[] args) {
BigDecimal e = new BigDecimal(0.0);
int PRECISION = 15;
int iterations = 0;
for(int i = 0; i < PRECISION; i++)
{
iterations++;
BigDecimal numerator = new BigDecimal(1.0); // to divide, we need two BigDecimals, the numerator is 1
BigDecimal factorial = new BigDecimal(calcDenominator(i)); // the denominator is i! which we get from calling the factorial method
factorial = numerator.divide(factorial, PRECISION, BigDecimal.ROUND_UNNECESSARY); // compute 1/i!, note divide is overloaded, this version is used to
// ensure a limit to the iterations when division is limitless like 1/3
e = e.add(factorial); // add the latest 1/i! to e
}
System.out.println("Computed value of e : " + e);
System.out.println("Expected value of e : " + Math.E);
}
}
Rounding is necessary here. Use something like HALF_EVEN. Even better, use the enum value RoundingMode.HALF_EVEN, because the integer constants for rounding mode are deprecated.
In calcDenominator, change your for loop condition to i <= n, or else you'll add 1 one too many times in main and you'll get a value that's 1 too high.
You can use BigDecimal.ONE to initialize numerator. This doesn't affect the result, but why create an unnecessary object? Same comment on the initialization of e, except with BigDecimal.ZERO.
You are using the first PRECISION terms of an infinite series (Maclaurin Series) that approximates e, an irrational number. There is an error term when you cut off the for loop, and that is expected mathematically. With the above changes, and bumping PRECISION to 50, I get the following, which looks sufficiently precise.
Computed value of e : 2.71828182845904523536028747135266249775496954201584
Expected value of e : 2.718281828459045
It is precise, despite using the double constructor for BigDecimal because the significant digits for a double start with the first non-zero bit, so even if you're calculating 1/n! for large n, the significant digits are good enough for adding to the existing approximation for e.

how to create an Exp(-x^2) function?

I am using the "think java" book and I am stuck on exercise 7.6. The goal here is to write a function that can find . It gives you a couple hints:
One way to evaluate is
to use the infinite series expansion:
In other words, we need to add up a series of terms where the ith term
is equal to
Here is the code I came up with, but it is horribly wrong (when compared to Math.exp) for anything other than a power of 1. I don't understand why, as far as I can tell the code is correct with the formula from the book. I'm not sure if this is more of a math question or something related to how big of a number double and int can hold, but I am just trying to understand why this doesn't work.
public static void main(String[] args) {
System.out.println("Find exp(-x^2)");
double x = inDouble("Enter x: ");
System.out.println("myexp(" + -x*x + ") = " + gauss(x, 20));
System.out.println("Math.exp(" + -x*x + ") = " + Math.exp(-x*x));
}
public static double gauss(double x, int n) {
x = -x*x;
System.out.println(x);
double exp = 1;
double prevnum = 1;
int prevdenom = 1;
int i = 1;
while (i < n) {
exp = exp + (prevnum*x)/(prevdenom*i);
prevnum = prevnum*x;
prevdenom = prevdenom*i;
i++;
}
return exp;
} // I can't figure out why this is so inacurate, as far as I can tell the math is accurate to what the book says the formula is
public static double inDouble(String string) {
Scanner in = new Scanner (System.in);
System.out.print(string);
return in.nextDouble();
}
I am about to add to the comment on your question. I do this because I feel I have a slightly better implementation.
Your approach
Your approach is to have the function accept two arguments, where the second argument is the number of iterations. This isn't bad, but as #JamesKPolk pointed out, you might have to do some manual searching for an int (or long) that won't overflow
My approach
My approach would use something called the machine epsilon for a data type. The machine epsilon is the smallest number of that type (in your case, double) that is representable as that number. There exists algorithm for determining what that machine epsilon is, if you are not "allowed" to access machine epsilon in the Double class.
There is math behind this:
The series representation for your function is
Since it is alternating series, the error term is the absolute value of the first term you choose not to include (I leave the proof to you).
What this means is that we can have an error-based implementation that doesn't use iterations! The best part is that you could implement it for floats, and data types that are "more" than doubles! I present thus:
public static double gauss(double x)
{
x = -x*x;
double exp = 0, error = 1, numerator = 1, denominator = 1;
double machineEpsilon = 1.0;
// calculate machineEpsilon
while ((1.0 + 0.5 * machineEpsilon) != 1.0)
machineEpsilon = 0.5 * machineEpsilon;
int n = 0; //
// while the error is large enough to be representable in terms of the current data type
while ((error >= machineEpsilon) || (-error <= -machineEpsilon))
{
exp += error;
// calculate the numerator (it is 1 if we just start, but -x times its past value otherwise)
numerator = ((n == 0) ? 1 : -numerator * x);
// calculate the denominator (denominator gets multiplied by n)
denominator *= (n++);
// calculate error
error = numerator/denominator;
}
return exp;
}
Let me know how this works!

Function giving incorrect result

I know something is wrong with my variables storing the info.
At the end of the program, it prints 0.0 for rate.
I have been trying to figure out the error in logic or syntax in my program. I believe it may have something to do with the variables being 0, I have also tried inserting the function into the loop when count == floor.
import javax.swing.*;
public class pickanumber {
public static void main(String[] args) {
int floor=1, rooms, occupants, rsum = 0, osum = 0;
String amount;
do {
amount = JOptionPane.showInputDialog("Enter total floors.");
floor = Integer.parseInt(amount);
} while (floor <= 0);
for (int count = 1; count <= floor; count++) {
if (floor==13) count++;
do {
amount = JOptionPane.showInputDialog("Enter total rooms on floor "+count+".");
rooms = Integer.parseInt(amount);
} while(rooms <= 9);
rsum += rooms;
do {
amount = JOptionPane.showInputDialog("Enter occupants on floor "+count+".");
occupants = Integer.parseInt(amount);
} while ((occupants > rooms)||(occupants < 0));
osum += occupants;
}
int rate = (osum/rsum)*100;
JOptionPane.showInputDialog("occupancy is at "+rate+"% capacity.");
}
}
osumand rsum are both integers, they represent numbers without decimal.
Any math opertion using only those 2 integers will return an integer.
So osum/rsum will return
0 if osum < rsum
1 if rsum <= osum < 2*rsum
etc.
If you want to get the decimal value of this division, you can
define your rate as double type in order to contain decimal numbers.
cast at least one of your varaible as a double in the operation
You should end with something like:
double rate = (((double) osum)/rsum)*100;
The problem lies within the datatypes i guess (or atleast i couldn't think of anything else). the result of (osum/rsum) must be integer, and will therefor nearly always be 0 (or 1, if osum == rsum). Simply cast them to double before the division, and cast the result of the complete calculation back to integer, and things should work quite fine.
Double drsum = (double) rsum;
Double dosum = (double) osum;
Double rate = (dosum/drsum)*100;
int i = rate.intValue();

decimal number to utf-8 rational number in Java

i want to change 2.5 to 2½. Not sure how to change it.
Let say I have “AMZN 2½ 22” in a long text that I have to highlight in java swing textpane but I have values in three variable as below
A = AMZN
B = 2.5
C = 22
Based on this value I will not be able to match so changing B to Rational number (String) and then matching and it’s working fine but I don’t want to do this… it’s just a temp fix.
Can someone help me ?
B = B.toString().replace(".25", "¼")
.replace(".5", "½")
.replace(".75", "¾")
.replace(".375", "⅜")
.replace(".625", "⅜")
.replace(".125", "⅛")
.replace(".875", "⅞")
.replace(".0", "")
.replace(".000", "")
.replace(".00", "");
Thanks
Here's how to print the symbol 'half':
String half = "\u20BD";
System.out.println("2" + half);
determining if a number is an integer plus half is left as an exercise to the reader.
You can swap .0 replaces with a regex (replaceAll("\\.[^1-9]+","" comes to mind), you can move the replaces to a map or utility class, have them happen only when Float.parseFloat(var) doesn't throw NumberFormatException...
But there is no truly better way to do such arbitrary replaces. Those unicode strings have no intrinsic connection with the numbers they represent that you could use.
There are two alternatives for real numbers: double (an approximation of a real number) or BigDecimal (maintaining a precission).
String a = "AMZN";
BigDecimal b = new BigDecimal("2.5");
double b2 = 2.5;
int c = 22;
// %s = string, %f = floating point, %d = digits, %n = newline.
System.out.printf("%s %f %d%n", a, b2, c);
For double you have not really any control but you might format the output (printf) using "%.3f" for a precission of 3 decimals.
In your case you want to represent the numbers using fractions from the Unicode.
Let's do that with the less suited double:
System.out.printf("%s %s %d%n", a, asFraction(b2), c);
static String[] fractionTexts = { "", "¼", "½", ... }; // Maybe char
static double[] fractionValues = { 0.0, 0.25, .5, ... };
static String asFraction(double x) {
if (x < 0) {
return "\u2212" + asFraction(-x); // U+2212 is Unicode minus.
}
long integralPart = (long)x;
double decimalsPart = x - integralPart;
for (int i = 0; i < fractionValues.length; ++i) {
if (almostEqual(decimalsPart, fractionValues[i]) {
decimalPoint = "";
return MessageFormat("{0}", integralPart) + fractionTexts[i];
}
}
return MessageFormat("{0}", x);
}
private boolean almostEqual(double x, double y) {
final double EPS = 0.0001;
return x >= y - EPS && x <= y + EPS;
}
The code uses MessageFormat for thousand separators / decimal separator. For 0.0, 0.00, 0.00ß0 (the same number) it leaves away the numbers explicitly. The java source code must be in the same encoding as the java compiler and be able to hold ¼ and others (like UTF-8).
For the error bearing double I have introduced almostEqual.

Calculating the value of a mathematical function in Java

I have this function and I was trying to get a list of all the calculations.
f(x) = (100)(1.1)^X
How do I calculate this out in Java. I tried a for loop to get the value of x and the end result of y, but that didn't work. Might have been my code inside. I tried to get the exponent of 1.1 and the multiply that by 100, is this correct?
for(int i = 1; i<=15; i++){
int expcalc = (int) Math.pow(1.1, i);
int finalcalc = price * expcalc;
System.out.println(" " + finalcalc);
}
What am I doing wrong here?
Why are you casting the result as an int? That will drop everything past the decimal point. Declare expcalc and finalcalc as double instead to obtain an accurate result.
double expcalc = Math.pow(1.1, i);
double finalcalc = price * expcalc;
Use BigDecimal if you're using pow() and decimal values, and ESPECIALLY ON MONEY
Assuming your interpretation is correct,
BigDecimal price = new BigDecimal("0.0"); //change this value to your price
for(int i = 1; i<=15; i++){
BigDecimal expcalc = new BigDecimal("1.1").pow(i);
BigDecimal finalcalc = price.multiply(expcalc);
System.out.println(" " + finalcalc);
}
Avoid using double/float on monetary computations.

Categories

Resources