#include "pico/float.h" // Required for using single-precision variables.
#include "pico/double.h" // Required for using double-precision variables.
#include "hardware/timer.h"
#include <stdio.h>
#include "pico/stdlib.h"
#include "pico/multicore.h"
#define FLAG_VALUE 123
void core1_entry() {
while (1) {
// Function pointer is passed to us via the FIFO
// We have one incoming int32_t as a parameter, and will provide an
// int32_t return value by simply pushing it back on the FIFO
// which also indicates the result is ready.
int32_t (*func)() = (int32_t(*)()) multicore_fifo_pop_blocking();
int32_t p = multicore_fifo_pop_blocking();
int32_t result = (*func)(p);
multicore_fifo_push_blocking(result);
}
}
/**
* @brief Computes the approximation of Pi using the Wallis algorithm with
* single-precision floating point.
*
* @param n Number of iterations for the Wallis product.
* @return float The computed approximation of Pi.
*/
float wallisAlgorithmFloat(int n);
/**
* @brief Computes the approximation of Pi using the Wallis algorithm with
* double-precision floating point.
*
* @param n Number of iterations for the Wallis product.
* @return double The computed approximation of Pi.
*/
double wallisAlgorithmDouble(int n);
/**
* @brief Calculates the approximation error for Pi, using the expected value of Pi.
*
* @param piAcc The calculated value of Pi.
* @return float The percentage error in the approximation.
*/
float approximateError(float piAcc);
#define TEST_NUM 10
/**
* @brief Main entry point for the code. Runs the Wallis algorithm for both float
* and double precision, and calculates the approximation error.
*
* @return int Returns exit-status zero on completion.
*/
int main() {
#ifndef WOKWI
// Initialise the IO as we will be using the UART
// Only required for hardware and not needed for Wokwi
stdio_init_all();
#endif
// Print a console message to inform user what's going on.
// printf("Hello World!\n");
const int ITER_MAX = 100000;
multicore_launch_core1(core1_entry);
// Code for sequential run goes here…
printf("Run in sequential\n");
// Run the Wallis algorithm with float precision and print the result
float piCalF = wallisAlgorithmFloat(100000);
printf("float: %f \n", piCalF);
printf("Approximation error: %f \n", approximateError(piCalF));
// Run the Wallis algorithm with double precision and print the result
double piCalD = wallisAlgorithmDouble(100000);
printf("double: %f \n", piCalD);
printf("Approximation error: %f \n", approximateError(piCalD));
// Code for parallel run goes here…
printf("Run in parallel\n");
uint64_t mulDoubleStart = time_us_64();
multicore_fifo_push_blocking((uintptr_t) &wallisAlgorithmFloat);
multicore_fifo_push_blocking(ITER_MAX);
double piCalculationDouble = wallisAlgorithmDouble(ITER_MAX);
float piCalculationFloat = multicore_fifo_pop_blocking();
// double piTwoDec = 4.0/3.0;
// for(int i = 2; i< ITER_MAX; i++){
// piTwoDec *= ((4.0*i*i) / (4.0*(i*i) -1));
// }
uint64_t mulDoubleFin = time_us_64();
// Print results
printf("float (Core 1): %f \n", piCalculationDouble);
printf("double (Core 0): %f \n", piCalculationFloat);
// Print approximation errors
printf("Approximation error (float): %f \n", approximateError(piCalculationFloat));
printf("Approximation error (double): %f \n", approximateError(piCalculationDouble));
// Print total time for parallel execution
printf("Total time in parallel mode: %.3f seconds \n", (mulDoubleFin - mulDoubleStart) / 1000000.0);
// float resultmf = multicore_fifo_pop_blocking();
// Take snapshot of timer and store
// Run the single-precision Wallis approximation on one core
// Run the double-precision Wallis approximation on the other core
// Take snapshot of timer and store
// Display time taken for application to run in parallel mode
// return 0;
// Returning zero indicates everything went okay.
return 0;
}
/**
* @brief Computes Pi using the Wallis algorithm in single-precision floating point.
*
* @param n Number of iterations for the Wallis product.
* @return float The computed value of Pi.
*/
float wallisAlgorithmFloat(int n){
uint64_t time = time_us_64();
float pi = 1.0;
float left;
float right;
for(float i=1.0; i<=n; i++){
left = (float)(2*i / ((2*i)-1));
right = (float)(2*i / ((2*i)+1));
pi = pi * (left * right);
}
printf("Calulating Pi(Float) took %.3f seconds \n", ((time_us_64() - time) / 1000000.0));
return pi * 2;
}
/**
* @brief Computes Pi using the Wallis algorithm in double-precision floating point.
*
* @param n Number of iterations for the Wallis product.
* @return double The computed value of Pi.
*/
double wallisAlgorithmDouble(int n){
uint64_t time = time_us_64();
double pi = 1.0;
double left;
double right;
for(double i=1.0; i<=n; i++){
left = (double)(2*i / ((2*i)-1));
right = (double)(2*i / ((2*i)+1));
pi = pi * (left * right);
}
printf("Calulating Pi(Double) took %.3f seconds \n", ((time_us_64() - time) / 1000000.0));
return pi * 2;
}
/**
* @brief Computes the percentage approximation error of a calculated Pi value.
*
* @param piAcc The calculated value of Pi.
* @return float The approximation error as a percentage.
*/
float approximateError(float piAcc){
float piExp = 3.14159265359;
return ((piExp - piAcc) / piAcc) * 100;
}