Calculating sin function with JAVA BigDecimal -monomial is going bigger(?) - java

I'm making sin function with BigDecimal in JAVA, and this is as far as I go:
package taylorSeries;
import java.math.BigDecimal;
public class Sin {
private static final int cutOff = 20;
public static void main(String[] args) {
System.out.println(getSin(new BigDecimal(3.14159265358979323846264), 100));
}
public static BigDecimal getSin(BigDecimal x, int scale) {
BigDecimal sign = new BigDecimal("-1");
BigDecimal divisor = BigDecimal.ONE;
BigDecimal i = BigDecimal.ONE;
BigDecimal num = null;
BigDecimal result = x;
//System.err.println(x);
do {
x = x.abs().multiply(x.abs()).multiply(x).multiply(sign);
i = i.add(BigDecimal.ONE);
divisor = divisor.multiply(i);
i = i.add(BigDecimal.ONE);
divisor = divisor.multiply(i);
num = x.divide(divisor, scale + cutOff, BigDecimal.ROUND_HALF_UP);
result = result.add(num);
//System.out.println("d : " + divisor);
//System.out.println(divisor.compareTo(x.abs()));
System.out.println(num.setScale(9, BigDecimal.ROUND_HALF_UP));
} while(num.abs().compareTo(new BigDecimal("0.1").pow(scale + cutOff)) > 0);
System.err.println(num);
System.err.println(new BigDecimal("0.1").pow(scale + cutOff));
return result.setScale(scale, BigDecimal.ROUND_HALF_UP);
}
}
It uses Taylor series :
picture of the fomular
The monomial x is added every iteration and always negative number.
And the problem is, absolute value of x is getting bigger and bigger, so iteration never ends.
Is there and way to find them or better way to implement it from the first place?
EDIT:
I made this code from scratch with simple interest about trigonometric functions, and now I see lots of childish mistakes.
My intention first was like this:
num is x^(2k+1) / (2k+1)!
divisor is (2k+1)!
i is 2k+1
dividend is x^(2k+1)
So I update divisor and dividend with i and compute num by sign * dividend / divisor and add it to result by result = result.add(num)
so new and good-working code is:
package taylorSeries;
import java.math.BigDecimal;
import java.math.MathContext;
public class Sin {
private static final int cutOff = 20;
private static final BigDecimal PI = Pi.getPi(100);
public static void main(String[] args) {
System.out.println(getSin(Pi.getPi(100).multiply(new BigDecimal("1.5")), 100)); // Should be -1
}
public static BigDecimal getSin(final BigDecimal x, int scale) {
if (x.compareTo(PI.multiply(new BigDecimal(2))) > 0) return getSin(x.remainder(PI.multiply(new BigDecimal(2)), new MathContext(x.precision())), scale);
if (x.compareTo(PI) > 0) return getSin(x.subtract(PI), scale).multiply(new BigDecimal("-1"));
if (x.compareTo(PI.divide(new BigDecimal(2))) > 0) return getSin(PI.subtract(x), scale);
BigDecimal sign = new BigDecimal("-1");
BigDecimal divisor = BigDecimal.ONE;
BigDecimal i = BigDecimal.ONE;
BigDecimal num = null;
BigDecimal dividend = x;
BigDecimal result = dividend;
do {
dividend = dividend.multiply(x).multiply(x).multiply(sign);
i = i.add(BigDecimal.ONE);
divisor = divisor.multiply(i);
i = i.add(BigDecimal.ONE);
divisor = divisor.multiply(i);
num = dividend.divide(divisor, scale + cutOff, BigDecimal.ROUND_HALF_UP);
result = result.add(num);
} while(num.abs().compareTo(new BigDecimal("0.1").pow(scale + cutOff)) > 0);
return result.setScale(scale, BigDecimal.ROUND_HALF_UP);
}
}

The new BigDecimal(double) constructor is not something you generally want to be using; the whole reason BigDecimal exists in the first place is that double is wonky: There are almost 2^64 unique values that a double can represent, but that's it - (almost) 2^64 distinct values, smeared out logarithmically, with about a quarter of all available numbers between 0 and 1, a quarter from 1 to infinity, and the other half the same but as negative numbers. 3.14159265358979323846264 is not one of the blessed numbers. Use the string constructor instead - just toss " symbols around it.
every loop, sign should switch, well, sign. You're not doing that.
In the first loop, you overwrite x with x = x.abs().multiply(x.abs()).multiply(x).multiply(sign);, so now the 'x' value is actually -x^3, and the original x value is gone. Next loop, you repeat this process, and thus you definitely are nowhere near the desired effect. The solution - don't overwrite x. You need x, throughout the calculation. Make it final (getSin(final BigDecimal x) to help yourself.
Make another BigDecimal value and call it accumulator or what not. It starts out as a copy of x.
Every loop, you multiply x to it twice then toggle the sign. That way, the first time in the loop the accumulator is -x^3. The second time, it is x^5. The third time it is -x^7, and so on.
There is more wrong, but at some point I'm just feeding you your homework on a golden spoon.
I strongly suggest you learn to debug. Debugging is simple! All you really do, is follow along with the computer. You calculate by hand and double check that what you get (be it the result of an expression, or whether a while loop loops or not), matches what the computer gets. Check by using a debugger, or if you don't know how to do that, learn, and if you don't want to, add a ton of System.out.println statements as debugging aids. There where your expectations mismatch what the computer is doing? You found a bug. Probably one of many.
Then consider splicing parts of your code up so you can more easily check the computer's work.
For example, here, num is supposed to reflect:
before first loop: x
first loop: x - x^3/3!
second loop: x - x^3/3! + x^5/5!
etcetera. But for debugging it'd be so much simpler if you have those parts separated out. You optimally want:
first loop: 3 separated concepts: -1, x^3, and 3!.
second loop: +1, x^5, and 5!.
That debugs so much simpler.
It also leads to cleaner code, generally, so I suggest you make these separate concepts as variables, describe them, write a loop and test that they are doing what you want (e.g. you use sysouts or a debugger to actually observe the power accumulator value hopping from x to x^3 to x^5 - this is easily checked), and finally put it all together.
This is a much better way to write code than to just 'write it all, run it, realize it doesn't work, shrug, raise an eyebrow, head over to stack overflow, and pray someone's crystal ball is having a good day and they see my question'.

The fact that the terms are all negative is not the problem (though you must make it alternate to get the correct series).
The term magnitude is x^(2k+1) / (2k+1)!. The numerator is indeed growing, but so is the denominator, and past k = x, the denominator starts to "win" and the series always converges.
Anyway, you should limit yourself to small xs, otherwise the computation will be extremely lengthy, with very large products.
For the computation of the sine, always begin by reducing the argument to the range [0,π]. Even better, if you jointly develop a cosine function, you can reduce to [0,π/2].

Related

Find the modo value

I have given a log value Y , i want to calculate the anti log of Y i.e
ans = (Math.pow(10,Y))%mod
where mod = 1e9+7 and the anti log of Y will always be integer i.e Y is calculate as follow Y= log(a) a is very large integer of range 10^100000
So for given Y i need to calculate ans ? How to do that considering the mod operation.
My Approach
double D = Y -(int)Y
long Pow = (long)Y
for(int i=1;i<=Pow;i++) ans = (ans*10)%mod;
ans = (ans*Math.pow(10,D))%mod
But it's not correct can someone suggest be efficient approach here ? BigDecimal can be useful there ?
For Example:
Y = 16.222122660468525
Using the straight forward method and rounding off i.e Math.log(10,Y) give me 1667718169966651 but using loops it's give me 16677181699666510. I am not using mod now just explaining that there is an error.
Here Y is small so direct method works and we can take mod easily. if Y is range of 10000 it will not work and overflow so we have to used mod.
I guess it's should work
double D = Y -(int)Y
long Pow = (long)Y
for(int i=1;i<=Pow;i++) ans = (ans*10)%mod;
ans = (ans*Math.pow(10,D))
ans = Math.round(ans)
ans%=mod
There is an error in your judgement here - the loop method is not at fault.
The value of a in your example has 17 integer digits. From this stackoverflow post, a double has ~16 significant digits of precision. Thus both the loop and direct calculations are in fact being limited by lack of precision.
(Just to confirm, using a high precision calculator, the value of a is 16677181699666650.8689546562984070600381634077.... Thus both of your values are incorrect - unless you copied them wrongly?)
Thus your loop method is not the problem; you just need a
higher-precision method to do the last step (calculating pow(10, frac(Y))).
As a side note, there is a more efficient way of doing the loop part - this post has more details.

Is this an effective while loop?

Here is an assignment:
"Let's say you are given a number, a, and you want to find its
square root. One way to do that is to start with a very rough guess about
the answer, x0, and then improve the guess using the following formula
x1 = (x0 + a/x0)/2
For example, if we want to find the square root of 9, and we start with x0 = 6,
then x1 = (6 + 9/6)/2 = 15/4 = 3.75, which is closer.
We can repeat the procedure, using x1 to calculate x2, and so on. In this
case, x2 = 3.075 and x3 = 3.00091. So that is converging very quickly on the
right answer(which is 3).
Write a method called squareRoot that takes a double as a parameter and
that returns an approximation of the square root of the parameter, using this
technique. You may not use Math.sqrt.
As your initial guess, you should use a/2. Your method should iterate until
it gets two consecutive estimates that differ by less than 0.0001; in other
words, until the absolute value is less than 0.0001. You can use
Math.abs to calculate the absolute value."
This is exercise meant to practice while loop. As you see I did the assignment, I think it works ? But I am not sure how did I come to solution ? In other words, what should I improve here ? Is there any other way to enter the loop differently ? How to name variables more appropriately ? And lastly, is my approach good or bad here ?
public class squareRoot {
public static void main(String args[]){
System.out.println(squareRoot(192.0));
}
public static double squareRoot(double a){
double gs = a/2; //guess
double ig = (gs + (a/gs))/2; //improving guess
double ig1 = (ig + (a/ig))/2; //one more improving guess, ig1
while (Math.abs((ig-ig1)) > 0.0001){ //with ig and ig1, I am entering the loop
ig = (ig1 + (a/ig1))/2;
ig1 = (ig + (a/ig))/2; //ig1 has to be less then ig
}
return ig1;
}
}
Your approach is nearly correct.
Let's talk about variables first. IMO, you should use full names for variables instead of acronyms. Use guess instead of gs. Use improvedGuess instead of ig etc.
Now that's out of the way we can see where your problem lies. For the while loop to finish, two consecutive guesses' difference must be less than 0.0001. However, here you are only comparing the 1st and 2nd guesses, the 3rd and 4th guesses, the 5th and 6th guesses etc. What if the 4th and 5th guesses' difference is less than 0.0001? Your loop won't stop. Instead, it returns the value of the 6th guess. Although it is more accurate, it does not fulfill the requirement.
Here's what I've come up with
public static double squareRoot(double a){
double guess = a/2;
double improvedGuess = (guess + (a/guess))/2;
while (Math.abs((guess - improvedGuess)) > 0.0001){
guess = improvedGuess;
improvedGuess = (guess + (a/guess))/2;
}
return improvedGuess;
}
Here is my Solution
private static double squareRoot(double a){
double x0= a/2;
while (true) {
double x1 = (x0 + a / x0) / 2;
if (Math.abs(x1 - x0) < 0.0001) {
break;
}
x0=x1;
}
return x0;
}

In Java, how to achieve this type of number rounding?

I am writing a small physics app. What I am planning to do is to make number rounding. The issue is that it is not a fixed rounding, but rather a variable rounding that depends on the value of the decimal digits. I will give an explanation for the issue.
I always need to keep the whole integer part (if any) and the first five decimal digits (if any).
half up rounding is always used.
21.1521421056 becomes 21.15214
34.1521451056 becomes 34.15215
If the result consists of only decimal digits then:
If the first five digits include non zero digits then keep them.
0.52131125 becomes 0.52131
0.21546874 becomes 0.21547
0.00120012 becomes 0.0012
If the first five digits are all zero digits 0.00000 then go down to first five digits that include non zero digits.
0.0000051234 becomes 0.0000051234
0.000000000000120006130031 becomes 0.00000000000012001
I need to play this rounding while working with BigDecimal because it is a requirement for my needs.
I think this will work, based on experimentation, if I understand correctly what you want. If d is a BigDecimal that contains the number:
BigDecimal rounded = d.round(new MathContext
(d.scale() - d.precision() < 5
? d.precision() - d.scale() + 5
: 5));
Is this, what you are looking for?
public static void main(String[] args){
double d = 0.000000000000120006130031;
System.out.println(round(d, 5));
}
private static double round(double d, int precision) {
double factor = Math.pow(10D, precision);
int value = (int)d;
double re = d-value;
if (re * factor <= 0.1 && d != 0) {
while (re * factor <= 0.1) {
factor *= 10;
}
factor *= Math.pow(10D, precision);
}
re = ((int)(re*factor))/factor+value;
return re;
}
(sorry, it's a little quick & dirty, but you can improve it, if you want)
EDIT:
make it <= in the conditions, this should work better

Convert fraction to decimal number

i'm doing some exercises in my Java book. I'm very new to programming. Therefore, notice (in the code) that i'm still on Chapter one. Now I already did everything, I just want a confirmation if this is legitimate so I can feel free to move on next.
If not, I would sincerely appreciate to not do my code for me; I want advice.
Here's the question written in the book,
"Write an application that prompts/reads the numerator and denominator of a fraction as integers, then prints the decimal equivalent of the fraction."
I'll illustrate this sentence with my code:
I did a revision here. Is this one OK?..
import java.util.*;
public class ExerciseEleven {
public static void main (String[] args) {
Scanner sc = new Scanner (System.in);
double fraction;
int fractionValue;
int decimal;
double value;
System.out.println("Enter Numerator: ");
int numerator = sc.nextInt();
System.out.println("Enter Denominator: ");
int denominator = sc.nextInt();
fraction = (double) numerator / denominator;
fractionValue = (int) (fraction * 10);
decimal = fractionValue % 10;
value = decimal * 0.1;
System.out.println(value);
}
}
It compiles and works fine.
Thank you.
It doesn't do what task says it should. You read doubles instead of integers, and the decimal equivalent is not what you print out. Decimal equivalent for 1/2 is 0.5. And you print 5.
Also, you can pay attention to your code style: variable names are usually written in lowerCamelCase, like that : simpleVariable.
Update
now it prints what you need. However you do it not in the very right way and your indentation can still be improved.
It's fine (I didn't read the assignment very well, did I? Kudos to Vladimir.) ...but some comments:
Usually you want to indent methods within the class.
Standard practice is to use initial caps (Numerator) only for types (e.g., classes, interfaces, enums). Variable, field, and method names should start with a lower-case letter. Now, you're free to ignore standard practice, but if you do people will have a lot of trouble reading your code. :-)
For rounding, you probably want to look at Math.round rather than truncating with a cast. But the assignment didn't say anything about rounding.
You might want to handle the case where denominator is zero.
So keeping those in mind:
import java.util.*;
public class ExcerciseEleven {
public static void main (String[] args) {
Scanner sc = new Scanner (System.in);
System.out.println("Enter Numerator: ");
int numerator = sc.nextInt();
System.out.println("Enter Denominator: ");
int denominator = sc.nextInt();
if (denominator == 0) {
System.out.println("Can't divide by zero");
}
else {
double fraction = (double)numerator / denominator;
System.out.println(fraction);
}
}
}
Hey I am doing some thinking about this and I have noticed something interesting after looking at this source and here is the Algorithm that I plan on implementing
First I will convert the number from the Metric using the
Javax.Measure family of functions and I will get a number like
0.3750
Then I will divide the number by ONE_SIXTEENTH which = 0.0625
ONE_SIXTEENTH = 0.0625
The answer 0.3750 / ONE_SIXTEENTH = 6;
So now I know there are 6 sixteenths of the inch
Next I check to see if 6 is divisible by 4, 6/4 = 1.5 ie not a whole number so the fraction is still regarded as 6/16th of an inch for now
Next I check to see if 6 is divisible by 2, 6/2 = 3
This is a whole number so we will use it to reconstitute the fraction
So now that we have divided 6 by 2 and gotten 3 the 16 needs to be divided by 2 and we end up with 8 so 6/16th of an inch becomes 3/8th of an inch.
PS Has anyone noticed that this is similar to a fizz bang program?
____________________________________________
Here is the chart which helped me get my head around this
My workings
There are three important parts of division operation :
Sign of the result.
Integral part
Decimal part
Also, there are few corner cases where you need to deal with the fact that Integer.MIN_VALUE is greater than Integer.MAX_VALUE when compared in absolute form.
For example : -2147483648/-1 can't yield 2147483648 when divided in the form of integer types. The reason is simple. The type of the resulting type will be integer type, and the maximum positive value that a integer type variable can hold is +2147483647
To mitigate that scenario, we should at first convert both the numerator and denominator into their long positive form. That gives us the integral part of the answer.
The XOR of two numbers will have the sign bit as 1 only in case they have opposite signs. That solves the first part (sign of result) of the problem.
For decimal part, we can employ the general division rule i.e. multiply the remainder with 10 and try dividing again and repeat. Keep record of the remainder we have already come across to prevent the loop from going into unbounded iterations.
public String fractionToDecimal(int A, int B) {
StringBuilder sb = new StringBuilder((A^B) < 0 ? "-" : "");
long a = Math.abs((long)A);
long b = Math.abs((long)B);
sb.append(Long.toString(a/b));
long rem = a % b;
sb.append((rem != 0) ? "." : "");
Map<Long, Integer> remainderMap = new HashMap<>();
int pos = 0;
while (rem != 0){
sb.append(Long.toString((rem*10)/b));
remainderMap.put(rem, pos++);
rem = (rem*10) % b;
if (remainderMap.containsKey(rem)){
String currNum[] = sb.toString().split("\\.");
return currNum[0] + "." + currNum[1].substring(0, remainderMap.get(rem)) +
"(" + currNum[1].substring(remainderMap.get(rem)) + ")";
}
}
if (sb.toString().equals("-0")) return "0";
return sb.toString();
}
Sample output :
2/3 gives 0.(6)
-2147483648/-1 gives 2147483648

How can I turn a floating point number into the closest fraction represented by a byte numerator and denominator?

How can I write an algorithm that given a floating point number, and attempts to represent is as accurately as possible using a numerator and a denominator, both restricted to the range of a Java byte?
The reason for this is that an I2C device wants a numerator and denominator, while it would make sense to give it a float.
For example, 3.1415926535... would result in 245/78, rather than 314/100 or 22/7.
In terms of efficiency, this would be called around three times at the start of the program, but after that not at all. So a slow algorithm isn't too bad.
Here's the code I used in the end (based on uckelman's code)
public static int[] GetFraction(double input)
{
int p0 = 1;
int q0 = 0;
int p1 = (int) Math.floor(input);
int q1 = 1;
int p2;
int q2;
double r = input - p1;
double next_cf;
while(true)
{
r = 1.0 / r;
next_cf = Math.floor(r);
p2 = (int) (next_cf * p1 + p0);
q2 = (int) (next_cf * q1 + q0);
// Limit the numerator and denominator to be 256 or less
if(p2 > 256 || q2 > 256)
break;
// remember the last two fractions
p0 = p1;
p1 = p2;
q0 = q1;
q1 = q2;
r -= next_cf;
}
input = (double) p1 / q1;
// hard upper and lower bounds for ratio
if(input > 256.0)
{
p1 = 256;
q1 = 1;
}
else if(input < 1.0 / 256.0)
{
p1 = 1;
q1 = 256;
}
return new int[] {p1, q1};
}
Thanks for those who helped
I've written some code (in Java, even) to do just the thing you're asking for. In my case, I needed to display a scaling factor as both a percentage and a ratio. The most familiar example of this is the zoom dialog you see in image editors, such as the GIMP.
You can find my code here, in the updateRatio() method starting at line 1161. You can simply use it, so long as the LGPL license works for you. What I did essentially follows what's done in the GIMP---this is one of those things where there's pretty much only one efficient, sensible way to do it.
How worried are you about efficiency? If you're not calling this conversion function 100s of times per second or more, then it probably wouldn't be all that hard to brute-force through every possible denominator (most likely only 255 of them) and find which one gives the closest approximation (computing the numerator to go with the denominator is constant time).
I would comment, but I don't have rep yet...
Eric's answer above doesn't consider the case where an exact result is possible. For example, if you use 0.4 as input, then the representation should be 2/5, in which case you end up with a division by zero in the third iteration of the loop (r=0 on second loop => r = 1/r error on third).
So you want to modify the while loop to exclude that option:
while(true)
should be
while(r != 0)
You should look at the Farey Sequence.
Given a limit on the denominator d, the Farey Sequence is every fraction having denominator <= d.
Then, you would simply take your float and compare it to the resolved value of the Farey fraction. This will allow you to represent your float in terms of repeating-decimal reals.
Here is a page on its implementation in java:
http://www.merriampark.com/fractions.htm
Here is a good demonstration of their use:
http://www.maths.surrey.ac.uk/hosted-sites/R.Knott/Fractions/fareySB.html
What about using Apache's BigFraction:
import org.apache.commons.math3.fraction.BigFraction;
public static BigFraction GetBigFraction(double input)
{
int precision = 1000000000;
return new BigFraction((int)(input * (double)precision), precision);
}
I reached out here out of curiosity, but I remembered there's such feature in Python standard library fractions.
Maybe, we can look into the source code of the two functions:
Fraction.from_float
Fraction.limit_denominator

Categories

Resources