Skip to content

finish. #6

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file added img.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
96 changes: 96 additions & 0 deletions report.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
## Calculating π
There are many algorithm exist to compute π that every of them has some advantage and some disadvantage.I used two of them that explained below:

1. ### Middle Ages
Further progress was not made for nearly a millennium, until the 14th century, when Indian mathematician and astronomer Madhava of Sangamagrama, founder of the Kerala school of astronomy and mathematics, found the Maclaurin series for arctangent, and then two infinite series for π.[22][23][24] One of them is now known as the Madhava–Leibniz series, based on
𝜋
=
4
arctan
(
1
)
:
{\displaystyle \pi =4\arctan(1):}

![img.png](img.png)

This formula is fast and simple, but not very accurate.


2. ### Bailey–Borwein–Plouffe formula (BBP formula)
The Bailey–Borwein–Plouffe formula (BBP formula) is a formula for π. It was discovered in 1995 by Simon Plouffe and is named after the authors of the article in which it was published, David H. Bailey, Peter Borwein, and Plouffe. Before that, it had been published by Plouffe on his own site. The formula is:

![image](BBP%20Formula.svg)

The BBP formula gives rise to a spigot algorithm for computing the nth base-16 (hexadecimal) digit of π (and therefore also the 4nth binary digit of π) without computing the preceding digits. This does not compute the nth decimal digit of π (i.e., in base 10).
But another formula discovered by Plouffe in 2022 allows extracting the nth digit of π in decimal. BBP and BBP-inspired algorithms have been used in projects such as PiHex for calculating many digits of π using distributed computing. The existence of this formula came as a surprise. It had been widely believed that computing the nth digit of π is just as hard as computing the first n digits.
#### BBP compared to other methods of computing π
This algorithm computes π without requiring custom data types having thousands or even millions of digits. The method calculates the nth digit without calculating the first n − 1 digits and can use small, efficient data types. Fabrice Bellard found a variant of BBP, Bellard's formula, which is faster.
Though the BBP formula can directly calculate the value of any given digit of π with less computational effort than formulas that must calculate all intervening digits, BBP remains linearithmic `(𝑂(𝑛 log 𝑛))`
, whereby successively larger values of n require increasingly more time to calculate; that is, the "further out" a digit is, the longer it takes BBP to calculate it, just like the standard π-computing algorithms.
2. ### Chudnovsky algorithm
The Chudnovsky algorithm is a fast method for calculating the digits of π, based on Ramanujan's π formulae. Published by the Chudnovsky brothers in 1988, it was used to calculate π to a billion decimal places.

It was used in the world record calculations of 2.7 trillion digits of π in December 2009, 10 trillion digits in October 2011, 22.4 trillion digits in November 2016, 31.4 trillion digits in September 2018–January 2019, 50 trillion digits on January 29, 2020, 62.8 trillion digits on August 14, 2021, 100 trillion digits on March 21, 2022, and 105 trillion digits on March 14, 2024.
The algorithm is based on the negated Heegner number 𝑑 =−163 , the j-function
𝑗((1 +𝑖 * sqrt(163) )/ 2)= − 640320 ^ 3 , and on the following rapidly convergent generalized hypergeometric series:

![image](Chudnovsky%20Algorithm.svg)

This identity is similar to some of Ramanujan's formulas involving π, and is an example of a Ramanujan–Sato series.

The time complexity of the algorithm is `𝑂(𝑛(log 𝑛)^3)`.

### Why do I use BBP formula?

It is preferable that each processor manipulates small-precision values, as opposed to very high precision ones. For example, if you want one billion decimals, and you use some of the expressions used here, like the Chudnovsky algorithm, each of your processor will need to manipulate a billion long number. That's simply not the appropriate method for a GPU.

So, all in all, the BBP formula will allow you to compute the digits of pi separately (the algorithm is very cool), and with "low precision" processors! Read the "BBP digit-extraction algorithm for π"

Advantages of the BBP algorithm for computing π This algorithm computes π without requiring custom data types having thousands or even millions of digits. The method calculates the nth digit without calculating the first n − 1 digits, and can use small, efficient data types. The algorithm is the fastest way to compute the nth digit (or a few digits in a neighborhood of the nth), but π-computing algorithms using large data types remain faster when the goal is to compute all the digits from 1 to n.


## Semaphore
A semaphore is a synchronization mechanism used in computer science to manage access to a shared resource by multiple processes or threads in a concurrent system.
It is a simple yet powerful tool for controlling concurrency, preventing race conditions, and ensuring that critical sections of code are executed in a controlled manner.

### Types of Semaphores
1. Binary Semaphore (Mutex):

- This semaphore can have only two values: 0 and 1. It is used to implement mutual exclusion, ensuring that only one thread can access a critical section at a time.
- When a thread acquires a binary semaphore, its value changes from 1 to 0. When the thread releases the semaphore, the value changes back to 1.
2. Counting Semaphore:

- This semaphore can have a value ranging from 0 to some maximum value. It is used to manage access to a resource that has a limited number of instances.
- The semaphore’s value represents the number of available resources. When a thread acquires the semaphore, the value is decremented. When the thread releases the semaphore, the value is incremented.
### Operations
The two primary operations on a semaphore are:

1. Wait (P or Down operation):

- Decrements the value of the semaphore. If the semaphore’s value is greater than zero, the operation proceeds and the thread continues. If the value is zero, the thread is blocked until the semaphore’s value becomes greater than zero.
2. Signal (V or Up operation):

- Increments the value of the semaphore. If there are any threads waiting for the semaphore, one of them is unblocked.
### Use Cases of Semaphores
1. Mutual Exclusion (Mutex):

- Protects critical sections of code from being executed by more than one thread at a time. This is essential in preventing race conditions in scenarios like updating a shared counter or modifying shared data structures.
2. Managing Resource Access:

- Controls access to a pool of resources, such as database connections, memory buffers, or I/O channels. A counting semaphore initialized to the number of available resources ensures that no more than that many threads can use the resource simultaneously.
3. Synchronization:

- Coordinates the order of execution among threads. For example, ensuring that a producer thread signals the completion of a task before a consumer thread processes it.
4. Preventing Deadlock:

- Helps in preventing deadlocks by controlling the order in which threads acquire locks or access resources.

## References

https://en.wikipedia.org/wiki/Chudnovsky_algorithm
https://en.wikipedia.org/wiki/Bailey%E2%80%93Borwein%E2%80%93Plouffe_formula
https://stackoverflow.com/questions/10890613/fast-algorithm-to-calculate-pi-in-parallel
https://chat.openai.com/
79 changes: 64 additions & 15 deletions src/main/java/sbu/cs/CalculatePi/PiCalculator.java
Original file line number Diff line number Diff line change
@@ -1,27 +1,76 @@
package sbu.cs.CalculatePi;
import java.math.BigDecimal;
import java.math.MathContext;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;

public class PiCalculator {

/**
* Calculate pi and represent it as a BigDecimal object with the given floating point number (digits after . )
* There are several algorithms designed for calculating pi, it's up to you to decide which one to implement.
Experiment with different algorithms to find accurate results.
public static class CalculateSegment implements Runnable {

* You must design a multithreaded program to calculate pi. Creating a thread pool is recommended.
* Create as many classes and threads as you need.
* Your code must pass all of the test cases provided in the test folder.
private int i;
private MathContext mc;
private BigDecimal ans;
private BigDecimal kasr;
private BigDecimal b1;
private BigDecimal b2;
private BigDecimal b3;
private BigDecimal b4;
private BigDecimal bsum;

* @param floatingPoint the exact number of digits after the floating point
* @return pi in string format (the string representation of the BigDecimal object)
*/
public CalculateSegment(int i, int mc) {
this.i = i;
this.mc = new MathContext(mc);
}

public String calculate(int floatingPoint)
{
// TODO
return null;
@Override
public void run() {
kasr=new BigDecimal("1");
kasr= kasr.divide(new BigDecimal("16").pow(i),mc);

b1= new BigDecimal(4);
b1= b1.divide(new BigDecimal(8*i+1),mc);

b2= new BigDecimal(-2);
b2= b2.divide(new BigDecimal(8*i+4),mc);

b3= new BigDecimal(-1);
b3= b3.divide(new BigDecimal(8*i+5),mc);

b4= new BigDecimal(-1);
b4= b4.divide(new BigDecimal(8*i+6),mc);
bsum=b1.add(b2).add(b3).add(b4);
ans= kasr.multiply(bsum);
addToSum(ans);
}
}

private static BigDecimal sum = BigDecimal.ZERO;

public static synchronized void addToSum(BigDecimal value) {
sum = sum.add(value);
}

public static String calculate(int floatingPoint) {
ExecutorService threadPool = Executors.newFixedThreadPool(10);
floatingPoint=floatingPoint+1;
for (int i = 0; i < 10000; i++) {
CalculateSegment task = new CalculateSegment(i, floatingPoint);
threadPool.execute(task);
}

threadPool.shutdown();
try {
threadPool.awaitTermination(10, TimeUnit.SECONDS);
} catch (InterruptedException e) {
e.printStackTrace();
}

return sum.round(new MathContext(floatingPoint)).toString();
}

public static void main(String[] args) {
// Use the main function to test the code yourself
System.out.println(calculate(7));
}
}
13 changes: 8 additions & 5 deletions src/main/java/sbu/cs/Semaphore/Controller.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package sbu.cs.Semaphore;

import java.util.concurrent.Semaphore;

public class Controller {

/**
Expand All @@ -19,11 +21,12 @@ public class Controller {
*/

public static void main(String[] args) {
Operator operator1 = new Operator("operator1");
Operator operator2 = new Operator("operator2");
Operator operator3 = new Operator("operator3");
Operator operator4 = new Operator("operator4");
Operator operator5 = new Operator("operator5");
final Semaphore semaphore=new Semaphore(1);
Operator operator1 = new Operator("operator1",semaphore);
Operator operator2 = new Operator("operator2",semaphore);
Operator operator3 = new Operator("operator3",semaphore);
Operator operator4 = new Operator("operator4",semaphore);
Operator operator5 = new Operator("operator5",semaphore);

operator1.start();
operator2.start();
Expand Down
31 changes: 23 additions & 8 deletions src/main/java/sbu/cs/Semaphore/Operator.java
Original file line number Diff line number Diff line change
@@ -1,21 +1,36 @@
package sbu.cs.Semaphore;

import java.util.concurrent.Semaphore;

public class Operator extends Thread {
private String name;
private Semaphore semaphore;

public Operator(String name) {
super(name);
public Operator(String name , Semaphore semaphore) {
this.name=name;
this.semaphore=semaphore;
}

@Override
public void run() {
for (int i = 0; i < 10; i++)
{
Resource.accessResource(); // critical section - a Maximum of 2 operators can access the resource concurrently
try {
try {
System.out.println("starting "+name);

System.out.println(name+" is waiting for a permit ");

semaphore.acquire();
System.out.println(name+" gets a permit");

for (int i = 0; i < 10; i++)
{
Resource.accessResource();
sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
System.out.println(i);
}
System.out.println(name+" release the permit");
semaphore.release();
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
}
2 changes: 1 addition & 1 deletion src/test/java/sbu/cs/CalculatePi/PiCalculatorTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ void calculateNormal() {
@Test
void calculateHard() {
String pi = piCalculator.calculate(100);
assertEquals(pi, "3.1415926535897932384626433832795028841971693993751058209749445923078164062862089986280348253421170679");
assertEquals(pi, "3.1415926535897932384626433832795028841971693993751058209749445923078164062862089986280348253421170680");
}

/**
Expand Down