From b05c37ed9954f34abbb88ba2116ea775fa103430 Mon Sep 17 00:00:00 2001 From: hadiali2006 Date: Tue, 28 Nov 2023 02:44:58 -0800 Subject: [PATCH] Recursive Mathematics Assignment --- Assignment03/ExtraCredit.java | 148 +++++++++++++++++++++++++++++ Assignment03/MathematicsRec.java | 157 +++++++++++++++++++++++++++++++ 2 files changed, 305 insertions(+) create mode 100644 Assignment03/ExtraCredit.java create mode 100644 Assignment03/MathematicsRec.java diff --git a/Assignment03/ExtraCredit.java b/Assignment03/ExtraCredit.java new file mode 100644 index 0000000..f038496 --- /dev/null +++ b/Assignment03/ExtraCredit.java @@ -0,0 +1,148 @@ +import java.io.BufferedWriter; +import java.io.File; +import java.io.FileOutputStream; +import java.io.FileWriter; +import java.io.IOException; +import java.nio.ByteBuffer; +import java.nio.channels.FileChannel; + +/** + * The class is designed for extra credit + * The student implements the fibby method using iterative approach + * and then benchmark with their recursive approach to draw conclusion + * @author Varik Hoang + * @author Hadi Ali + */ +public class ExtraCredit +{ + /** + * The method accepts non-negative integer and returns a value as described below + * @param theDecimalNumber is a non-negative decimal number (n) + * @return the value in following way: + * - return 1 when n = 0 + * - return sum of fibby(floor(n/4)) and fibby(floor(3n/4)) when n > 0 + */ + public static int fibby(int theDecimalNumber) { + if (theDecimalNumber == 0) { + return 1; + } + int[] table = new int[theDecimalNumber + 1]; + table[0] = 1; + + for (int i = 1; i <= theDecimalNumber; ++i) { + int firstArg = i / 4; + int secondArg = (3 * i) / 4; + table[i] = table[firstArg] + table[secondArg]; + } + return table[theDecimalNumber]; + } + + public static void main(String args[]) + { + int[] dataset = new int[] + { + 10, 25, 50, 75, 100, 125, 150, 175, 200, 225, 250, // small dataset + 500, 1000, 1500, 2000, 2500, 5000, 7500, 10000, 12500, 15000, 17500, // medium dataset + 25000, 50000, 75000, 100000, 200000, 500000, 1000000, 2000000 // large dataset + }; + + // sanity check the iterative fibby function + if (fibby(1000000) != MathematicsRec.fibby(1000000)) + { + System.err.println("Please make sure your iterative fibby correct before doing the benchmark"); + return; + } + + long sum; + int count; + int attempts = 5; + setContent("iterative_fibby.txt", ""); + setContent("recursive_fibby.txt", ""); + + // benchmarking + for (int value: dataset) + { + /** + * The iterative fibby + */ + fibby(value); + + // start benchmarking for each value + sum = 0; + count = attempts; + while (count --> 0) + { + long startTime = System.nanoTime(); + fibby(value); + long endTime = System.nanoTime(); + + // get the difference + sum += endTime - startTime; + } + // write out the execution time in nanoseconds (/1000000 in milliseconds) + appendContent("iterative_fibby.txt", (double) sum / attempts + "\n"); + + /** + * The recursive fibby + */ + MathematicsRec.fibby(value); + + // start benchmarking for each value + sum = 0; + count = attempts; + while (count --> 0) + { + long startTime = System.nanoTime(); + MathematicsRec.fibby(value); + long endTime = System.nanoTime(); + + // get the difference + sum += endTime - startTime; + } + // write out the execution time in nanoseconds (/1000000 in milliseconds) + appendContent("recursive_fibby.txt", (double) sum / attempts + "\n"); + } + } + + /** + * The method writes content to file (overwrite if file is existed) + * @param path the file along with the path + * @param content the content is written to file + */ + protected static void setContent(String path, String content) { setContent(new File(path), content); } + protected static void setContent(File file, String content) + { + BufferedWriter bw; + + try + { + bw = new BufferedWriter(new FileWriter(file)); + bw.write(content); + bw.flush(); + bw.close(); + } + catch (IOException ex) { System.err.println(ex.getMessage()); } + } + + /** + * The method appends content to file (overwrite if file is existed) + * @param path the file along with the path + * @param content the content is appended to file + */ + protected static void appendContent(String path, String content) { appendContent(new File(path), content); } + protected static void appendContent(File file, String content) + { + FileOutputStream fos; + + try + { + fos = new FileOutputStream(file, true); + + FileChannel channel = fos.getChannel(); + ByteBuffer buffer = ByteBuffer.wrap(content.getBytes("UTF-8")); + channel.write(buffer); + channel.close(); + } + catch (IOException ex) { System.err.println(ex.getMessage()); } + } +} \ No newline at end of file diff --git a/Assignment03/MathematicsRec.java b/Assignment03/MathematicsRec.java new file mode 100644 index 0000000..1167f1e --- /dev/null +++ b/Assignment03/MathematicsRec.java @@ -0,0 +1,157 @@ +/** + * The MathematicsRec class feature various methods that given number(s) perform different + * mathematical functions using only recursion. + * @author Hadi Ali + */ +class MathematicsRec { + /** + * The method returns a value which: + * - Increases each of even decimal digits of n by one + * - Decreases each of odd decimal digits of n by one + * @param theDecimalNumber the input decimal number (n) + * @return the new decimal number after digit adjustments + */ + public static long eduodd(final long theDecimalNumber) { + if (theDecimalNumber == 0) { + return 1; + } else if (theDecimalNumber < 0) { + return -eduodd(-theDecimalNumber); + } else { + long lastDigit = theDecimalNumber % 10; + long remainingDigits = theDecimalNumber / 10; + + if (lastDigit % 2 == 0) { + lastDigit += 1; + } else { + lastDigit -= 1; + } + + if (remainingDigits == 0) { + return lastDigit; + } + + return eduodd(remainingDigits) * 10 + lastDigit; + } + } + + /** + * The method accepts non-negative integer and returns a value as described below + * @param theDecimalNumber is a non-negative decimal number (n) + * @return the value in following way: + * - return 1 when n = 0 + * - return sum of fibby(floor(n/4)) and fibby(floor(3n/4)) when n > 0 + */ + public static int fibby(final int theDecimalNumber) { + if (theDecimalNumber == 0) { + return 1; + } + + int floorN4 = theDecimalNumber / 4; + int floor3N4 = (3 * theDecimalNumber) / 4; + + return fibby(floorN4) + fibby(floor3N4); + } + + + /** + * The method calls a method that prints all consecutive values of n and its fibby value + * @param theLowerBound the lower bound (start) + * @param theUpperBound the upper bound (end) + */ + + public static void stg(final int theLowerBound, final int theUpperBound) { + stg(theLowerBound, theUpperBound, -1); + } + + /** + * The method that recursively prints all consecutive values of n and its fibby value + * @param theCurrentNumber the current number that is recursively iterated by +1 (lower bound) + * @param theUpperBound the upper bound (end) + * @param thePreviousFibby the previous number from the fibby() method + */ + private static void stg(final int theCurrentNumber, final int theUpperBound, final int thePreviousFibby) { + if (theCurrentNumber > theUpperBound) return; + + int currentFib = fibby(theCurrentNumber); + if (currentFib != thePreviousFibby) { + System.out.println(theCurrentNumber + " " + currentFib); + } + + stg(theCurrentNumber + 1, theUpperBound, currentFib); + } + /** + * The method returns the median that split the array into 3 parts + * @param theList the list of integers (a) + * @return the median of the list of integers + */ + public static double median3(final int[] theList) { + return median3Helper(theList, 0, theList.length - 1); + } + + /** + * The method that recursively calculates the approximate median + * @param theList the list of integers (a) + * @param theLowerBound the lower bound (start) + * @param theUpperBound the upper bound (end) + * @return the median of the list of integers + */ + private static double median3Helper(final int[] theList, final int theLowerBound, final int theUpperBound) { + int length = theUpperBound - theLowerBound + 1; + + if (length == 1) { + return theList[theLowerBound]; + } + if (length == 2) { + return (theList[theLowerBound] + theList[theUpperBound]) / 2.0; + } + + int size = length / 3; + int remainder = length % 3; + int midStart, midEnd; + + if (remainder == 0) { + midStart = theLowerBound + size; + midEnd = theLowerBound + (2 * size) - 1; + } else if (remainder == 1) { + midStart = theLowerBound + size; + midEnd = theLowerBound + size + (length - 2 * size) - 1; + } else { + midStart = theLowerBound + size + 1; + midEnd = theLowerBound + 2 * size; + } + + double median1 = median3Helper(theList, theLowerBound, midStart - 1); + double median2 = median3Helper(theList, midStart, midEnd); + double median3 = median3Helper(theList, midEnd + 1, theUpperBound); + + return medianOfThree(median1, median2, median3); + } + + /** + * The method that finds the median of three numbers + * @param theMedian1Value value of the first median section + * @param theMedian2Value value of the second median section + * @param theMedian3Value value of the third median section + * @return the median of the original list of integers + */ + private static double medianOfThree(final double theMedian1Value, final double theMedian2Value, final double theMedian3Value) { + double max = theMedian1Value; + + if (theMedian2Value > max) { + max = theMedian2Value; + } + if (theMedian3Value > max) { + max = theMedian3Value; + } + + double min = theMedian1Value; + if (theMedian2Value < min) { + min = theMedian2Value; + } + if (theMedian3Value < min) { + min = theMedian3Value; + } + + return theMedian1Value + theMedian2Value + theMedian3Value - max - min; + } +} \ No newline at end of file