Phi Calculator


This is the only page on the site that isn’t focused on Pi. Instead, it features a calculator dedicated to the Golden RatioPhi (Φ).

Inspiration

While discussing the capabilities of large language models (LLMs) with my uncle, he stepped away and returned with a paper he had written in 1970 for his graduate architecture program. The topic was the Golden Ratio in architecture, and his calculations used the Fibonacci sequence to approximate Phi (Φ) to 15 decimal places. This inspired us to experiment with a C version of the calculation, comparing notes and exploring further.

The Golden Ratio

The Golden Ratio, often denoted by the Greek letter Phi (Φ), is an irrational number approximately equal to 1.6180339887…. It appears when a line is divided into two parts such that the ratio of the whole line to the longer part is the same as the ratio of the longer part to the shorter part. Mathematically, it is expressed as:

[math]\Phi = \frac{1 + \sqrt{5}}{2}[/math]

The Golden Ratio is widely observed in nature, art, and architecture, where it is often associated with aesthetic beauty and harmonious proportions. It is closely related to the Fibonacci sequence, as the ratio of consecutive Fibonacci numbers approaches Phi as the sequence progresses. Its unique properties have fascinated mathematicians, artists, and architects for centuries.

Sequences and Formulas

There are a number approaches for calculating The Golden Ratio. This program supports a Fibonacci Sequence, Continued Fraction, Binet’s Formula, and Newton’s Method. These are explained below:

Fibonacci Sequence

Definition: The Fibonacci sequence is a series of numbers where each number is the sum of the two preceding ones, starting with 0 and 1. This sequence approaches the value of Phi (Φ) as the ratio between consecutive Fibonacci numbers converges to Phi.

Formula:

[math]F_n = F_{n-1} + F_{n-2}, \quad F_0 = 0, \, F_1 = 1[/math]

The value of Phi is approached by the ratio:

[math]\Phi = \lim_{n \to \infty} \frac{F_{n+1}}{F_n}[/math]

Year: The Fibonacci sequence was introduced to the Western world in 1202 by Leonardo of Pisa (Fibonacci) in his book Liber Abaci.

Convergence: The convergence to Phi is slower because the ratio of consecutive Fibonacci numbers only gets closer to Phi with increasing, but it’s an effective way to approximate it.

Continued Fraction

Definition: A continued fraction is an expression obtained through an iterative process of representing a number as the sum of its integer part and the reciprocal of another number. The continued fraction for Phi is infinite.

Formula:

[math]\Phi = 1 + \cfrac{1}{1 + \cfrac{1}{1 + \cfrac{1}{1 + \cdots}}}[/math]

Year: The general concept of continued fractions dates back to ancient times but was formalized by John Wallis in 1655.

Convergence: Continued fractions give rapid convergence to Phi, requiring fewer terms to achieve high precision compared to the Fibonacci method.

Binet’s Formula

Definition: Binet’s formula directly calculates the n-th Fibonacci number using powers of Phi. It’s derived from the characteristic equation of the Fibonacci sequence.

Formula:

[math]F_n = \frac{\Phi^n – (1-\Phi)^n}{\sqrt{5}}[/math]

where [math]\Phi = \frac{1 + \sqrt{5}}{2}[/math] is the golden ratio.

Year: First published in 1843 by Jacques Philippe Marie Binet.

Convergence: Binet’s formula can give a quick approximation of Fibonacci numbers, but as n increases, the term (1-\Phi)^n diminishes, and the precision of the formula improves. For small n, there is noticeable divergence from Phi, but larger values of n bring it closer to convergence.

Newton’s Method

• Definition: Newton’s method is an iterative numerical technique for solving equations of the form f(x) = 0 . For Phi, the method solves the quadratic equation x^2 – x – 1 = 0 . • Formula:

[math]x_{n+1} = x_n – \frac{f(x_n)}{f{\prime}(x_n)}[/math]

For f(x) = x^2 – x – 1 , this becomes:

[math]x_{n+1} = x_n – \frac{x_n^2 – x_n – 1}{2x_n – 1}[/math]

Year: Newton’s method was developed by Sir Isaac Newton in 1669.

Convergence: Newton’s method converges very quickly when starting near the solution. However, it may diverge or converge slowly if the initial guess is far from the root. For calculating Phi, an initial guess close to \approx 1.6 helps achieve faster precision.

C Code
/*
==================================
==========================================
Phi Calculation Program - Version 1.0
Author: Chat GPT-4.0 (Prompting and quality testing by Derick Schaefer)
Date: 9/21/2024
==========================================

About:
  This program calculates the mathematical constant Phi (Φ) using different methods: 
  the Fibonacci method, the Continued Fraction method, Binet's Formula, and Newton's Method.
  It uses the MPFR library for high-precision arithmetic and allows the user to 
  specify the number of decimal points and output format.
  
  Usage:
  phicalculator <number_of_decimals> --format=<json,text> --method=<fibonacci,cfraction,binet,newton>

  Command Line Options:
  <number_of_decimals>: Number of decimal points or Fibonacci number index (for Binet's Formula and Newton's Method, used as iteration count)
  --format: Output format, either JSON or plain text
  --method: Method to calculate Phi, either "fibonacci", "cfraction", "binet", or "newton"
  If no format or method is provided, the default is "text" and "fibonacci".
==================================
*/

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <getopt.h>
#include <mpfr.h>

/*===============================
    Function Prototypes
===============================*/
void print_usage(const char *progname);
void truncate_decimal(char *phi_str, int decimal_points);
void output_phi_fibonacci(int decimal_points, const char *format);
void output_phi_cfraction(int decimal_points, const char *format);
void output_phi_binet(int n, const char *format);
void output_phi_newton(int decimal_points, const char *format);

/*===============================
    Utility Functions
===============================*/

/*
  print_usage: Displays the correct usage of the program.
*/
void print_usage(const char *progname) {
    printf("Usage: %s <number_of_decimals> --format=<json,text> --method=<fibonacci,cfraction,binet,newton>\n", progname);
}

/*
  truncate_decimal: Truncates the string representation of a number to a given number of decimal places.
*/
void truncate_decimal(char *phi_str, int decimal_points) {
    char *decimal_point = strchr(phi_str, '.');
    if (decimal_point != NULL) {
        decimal_point++;
        if (strlen(decimal_point) > decimal_points) {
            decimal_point[decimal_points] = '\0';  // Truncate after the specified decimal places
        }
    }
}

/*===============================
    Phi Calculation Functions
===============================*/

/*
  output_phi_fibonacci: Calculates Phi using the Fibonacci-based formula (1 + sqrt(5)) / 2 and prints the result.
*/
void output_phi_fibonacci(int decimal_points, const char *format) {
    mpfr_t phi, sqrt5, one, two;
    char *phi_str;
    size_t size;

    // Initialize MPFR variables with precision
    mpfr_init2(phi, decimal_points * 4);
    mpfr_init2(sqrt5, decimal_points * 4);
    mpfr_init2(one, decimal_points * 4);
    mpfr_init2(two, decimal_points * 4);

    // Set 1 and 2 as MPFR values
    mpfr_set_ui(one, 1, MPFR_RNDD);  
    mpfr_set_ui(two, 2, MPFR_RNDD);  

    // Calculate sqrt(5)
    mpfr_sqrt_ui(sqrt5, 5, MPFR_RNDD); 

    // Calculate Phi: (1 + sqrt(5)) / 2
    mpfr_add(phi, one, sqrt5, MPFR_RNDD);  
    mpfr_div(phi, phi, two, MPFR_RNDD);    

    // Convert Phi to string for output
    size = mpfr_snprintf(NULL, 0, "%.*Rf", decimal_points + 3, phi); 
    phi_str = malloc(size + 1);
    mpfr_snprintf(phi_str, size + 1, "%.*Rf", decimal_points + 3, phi);

    truncate_decimal(phi_str, decimal_points);

    // Output based on format
    if (strcmp(format, "json") == 0) {
        printf("{\"precision\": \"%d\", \"method\": \"fibonacci\", \"phi\": \"%s\"}\n", decimal_points, phi_str);
    } else {
        printf("Fibonacci Phi to %d decimal points: %s\n", decimal_points, phi_str);
    }

    free(phi_str);
    mpfr_clear(phi);
    mpfr_clear(sqrt5);
    mpfr_clear(one);
    mpfr_clear(two);
}

/*
  output_phi_cfraction: Calculates Phi using a Continued Fraction approach and prints the result.
*/
void output_phi_cfraction(int decimal_points, const char *format) {
    mpfr_t phi, one, temp;
    char *phi_str;
    size_t size;
    int iterations = 100;  // Number of iterations for the continued fraction

    // Initialize MPFR variables with precision
    mpfr_init2(phi, decimal_points * 4);
    mpfr_init2(one, decimal_points * 4);
    mpfr_init2(temp, decimal_points * 4);

    // Start with 1
    mpfr_set_ui(phi, 1, MPFR_RNDD);

    // Compute the continued fraction for Phi: 1 + 1/(1 + 1/(1 + 1/(...)))
    for (int i = 0; i < iterations; i++) {
        mpfr_set_ui(temp, 1, MPFR_RNDD);   // temp = 1
        mpfr_add(temp, temp, phi, MPFR_RNDD);  // temp = 1 + phi
        mpfr_ui_div(phi, 1, temp, MPFR_RNDD);  // phi = 1 / (1 + phi)
    }

    // Add the final 1 to complete the continued fraction
    mpfr_add_ui(phi, phi, 1, MPFR_RNDD); 

    // Convert Phi to a string
    size = mpfr_snprintf(NULL, 0, "%.*Rf", decimal_points + 3, phi); 
    phi_str = malloc(size + 1);
    mpfr_snprintf(phi_str, size + 1, "%.*Rf", decimal_points + 3, phi);

    // Manually truncate the string to the requested number of decimal places
    truncate_decimal(phi_str, decimal_points);

    // Output based on format
    if (strcmp(format, "json") == 0) {
        printf("{\"precision\": \"%d\", \"method\": \"cfraction\", \"phi\": \"%s\"}\n", decimal_points, phi_str);
    } else {
        printf("Continued Fraction Phi to %d decimal points: %s\n", decimal_points, phi_str);
    }

    // Free allocated memory
    free(phi_str);
    mpfr_clear(phi);
    mpfr_clear(one);
    mpfr_clear(temp);
}

/*
  output_phi_binet: Calculates an approximation of Phi using the ratio of Fibonacci numbers F(n+1) / F(n)
  based on Binet's Formula. Ensures output is formatted to exactly n decimal places.
*/
void output_phi_binet(int n, const char *format) {
    mpfr_t phi, one_minus_phi, sqrt5, result_n, result_n1, phi_n, one_minus_phi_n, phi_n1, one_minus_phi_n1;
    char *phi_str;
    size_t size;

    // Initialize MPFR variables with precision
    int decimal_points = n;  // Use n as the decimal point precision
    mpfr_init2(phi, decimal_points * 4);
    mpfr_init2(one_minus_phi, decimal_points * 4);
    mpfr_init2(sqrt5, decimal_points * 4);
    mpfr_init2(result_n, decimal_points * 4);
    mpfr_init2(result_n1, decimal_points * 4);
    mpfr_init2(phi_n, decimal_points * 4);
    mpfr_init2(one_minus_phi_n, decimal_points * 4);
    mpfr_init2(phi_n1, decimal_points * 4);
    mpfr_init2(one_minus_phi_n1, decimal_points * 4);

    // Set sqrt(5)
    mpfr_sqrt_ui(sqrt5, 5, MPFR_RNDD);

    // Set Phi = (1 + sqrt(5)) / 2 and 1 - Phi
    mpfr_set_ui(phi, 1, MPFR_RNDD);
    mpfr_add(phi, phi, sqrt5, MPFR_RNDD);
    mpfr_div_ui(phi, phi, 2, MPFR_RNDD);

    // Calculate 1 - Phi
    mpfr_ui_sub(one_minus_phi, 1, phi, MPFR_RNDD);

    // Calculate Phi^n and (1 - Phi)^n for n and n+1
    mpfr_pow_ui(phi_n, phi, n, MPFR_RNDD);
    mpfr_pow_ui(one_minus_phi_n, one_minus_phi, n, MPFR_RNDD);

        mpfr_pow_ui(phi_n1, phi, n + 1, MPFR_RNDD);
    mpfr_pow_ui(one_minus_phi_n1, one_minus_phi, n + 1, MPFR_RNDD);

    // Calculate the n-th and (n+1)-th Fibonacci numbers using Binet's formula
    mpfr_sub(result_n, phi_n, one_minus_phi_n, MPFR_RNDD);
    mpfr_div(result_n, result_n, sqrt5, MPFR_RNDD);

    mpfr_sub(result_n1, phi_n1, one_minus_phi_n1, MPFR_RNDD);
    mpfr_div(result_n1, result_n1, sqrt5, MPFR_RNDD);

    // Calculate the ratio F(n+1) / F(n) to approximate Phi
    mpfr_div(result_n1, result_n1, result_n, MPFR_RNDD);

    // Convert result to string for output
    size = mpfr_snprintf(NULL, 0, "%.*Rf", decimal_points, result_n1);  // Exact decimal points
    phi_str = malloc(size + 1);
    mpfr_snprintf(phi_str, size + 1, "%.*Rf", decimal_points, result_n1);

    // Output based on format
    if (strcmp(format, "json") == 0) {
        printf("{\"precision\": \"%d\", \"method\": \"binet\", \"phi\": \"%s\"}\n", decimal_points, phi_str);
    } else {
        printf("Binet Phi to %d decimal points: %s\n", decimal_points, phi_str);
    }

    // Free allocated memory
    free(phi_str);
    mpfr_clear(phi);
    mpfr_clear(one_minus_phi);
    mpfr_clear(sqrt5);
    mpfr_clear(result_n);
    mpfr_clear(result_n1);
    mpfr_clear(phi_n);
    mpfr_clear(one_minus_phi_n);
    mpfr_clear(phi_n1);
    mpfr_clear(one_minus_phi_n1);
}

/*
  output_phi_newton: Approximates Phi using Newton's method to solve the equation x^2 - x - 1 = 0.
*/
void output_phi_newton(int decimal_points, const char *format) {
    mpfr_t x_n, x_next, numerator, denominator, precision_diff;
    char *phi_str;
    size_t size;
    int iterations = 1000;  // Increase the number of iterations to ensure convergence
    double tolerance = 1e-20;  // Use a tighter tolerance for better precision

    // Initialize MPFR variables with precision
    mpfr_init2(x_n, decimal_points * 4);
    mpfr_init2(x_next, decimal_points * 4);
    mpfr_init2(numerator, decimal_points * 4);
    mpfr_init2(denominator, decimal_points * 4);
    mpfr_init2(precision_diff, decimal_points * 4);

    // Improved initial guess x_0 = 1.6 (closer to Phi)
    mpfr_set_d(x_n, 1.6, MPFR_RNDD);

    for (int i = 0; i < iterations; i++) {
        // Compute numerator: x_n^2 - x_n - 1
        mpfr_mul(numerator, x_n, x_n, MPFR_RNDD);  // x_n^2
        mpfr_sub(numerator, numerator, x_n, MPFR_RNDD);  // x_n^2 - x_n
        mpfr_sub_ui(numerator, numerator, 1, MPFR_RNDD);  // x_n^2 - x_n - 1

        // Compute denominator: 2*x_n - 1
        mpfr_mul_ui(denominator, x_n, 2, MPFR_RNDD);  // 2*x_n
        mpfr_sub_ui(denominator, denominator, 1, MPFR_RNDD);  // 2*x_n - 1

        // Compute next x: x_n - numerator / denominator
        mpfr_div(precision_diff, numerator, denominator, MPFR_RNDD);  // numerator / denominator
        mpfr_sub(x_next, x_n, precision_diff, MPFR_RNDD);  // x_next = x_n - (numerator / denominator)

        // Check for convergence
        mpfr_sub(precision_diff, x_next, x_n, MPFR_RNDD);
        if (mpfr_cmp_d(precision_diff, tolerance) < 0) {
            break;  // Converged
        }

        // Update x_n for the next iteration
        mpfr_set(x_n, x_next, MPFR_RNDD);
    }

    // Convert result to string for output
    size = mpfr_snprintf(NULL, 0, "%.*Rf", decimal_points, x_next);  // Exact decimal points
    phi_str = malloc(size + 1);
    mpfr_snprintf(phi_str, size + 1, "%.*Rf", decimal_points, x_next);

    // Output based on format
    if (strcmp(format, "json") == 0) {
        printf("{\"precision\": \"%d\", \"method\": \"newton\", \"phi\": \"%s\"}\n", decimal_points, phi_str);
    } else {
        printf("Newton Phi to %d decimal points: %s\n", decimal_points, phi_str);
    }

    // Free allocated memory
    free(phi_str);
    mpfr_clear(x_n);
    mpfr_clear(x_next);
    mpfr_clear(numerator);
    mpfr_clear(denominator);
    mpfr_clear(precision_diff);
}

/*===============================
    Main Function
===============================*/

/*
  main: The entry point of the program, parses command-line arguments and calls the appropriate Phi calculation function.
*/
int main(int argc, char *argv[]) {
    int decimal_points = -1;
    char format[10] = "text";   // Default format is text
    char formula[10] = "fibonacci";  // Default method is fibonacci

    // Long options for getopt_long
    static struct option long_options[] = {
        {"format", required_argument, 0, 0},
        {"method", required_argument, 0, 0},
        {0, 0, 0, 0}
    };

    int option_index = 0;
    int opt;

    // Check for valid number of arguments
    if (argc < 2) {
        print_usage(argv[0]);
        return 1;
    }

    // Parse the first argument as number of decimal points
    decimal_points = atoi(argv[1]);
    if (decimal_points <= 0) {
        printf("Error: Decimal points must be a positive number.\n");
        return 1;
    }

    // Parse the rest of the command-line arguments
    while ((opt = getopt_long(argc, argv, "", long_options, &option_index)) != -1) {
        if (opt == 0) {
            if (strcmp(long_options[option_index].name, "format") == 0) {
                strncpy(format, optarg, sizeof(format) - 1);
            } else if (strcmp(long_options[option_index].name, "method") == 0) {
                strncpy(formula, optarg, sizeof(formula) - 1);
            }
        } else {
            print_usage(argv[0]);
            return 1;
        }
    }

    // Call the appropriate Phi calculation function based on the method chosen
    if (strcmp(formula, "fibonacci") == 0) {
        output_phi_fibonacci(decimal_points, format);
    } else if (strcmp(formula, "cfraction") == 0) {
        output_phi_cfraction(decimal_points, format);
    } else if (strcmp(formula, "binet") == 0) {
        output_phi_binet(decimal_points, format);
    } else if (strcmp(formula, "newton") == 0) {
        output_phi_newton(decimal_points, format);
    } else {
        printf("Error: Unknown method type. Use 'fibonacci', 'cfraction', 'binet', or 'newton'.\n");
        return 1;
    }

    return 0;
}

Compilation and Use

To compile this code on a Debian-based Linux distribution (such as Ubuntu, Debian, or Raspbian), you will need to install the necessary precision math libraries and link to them during the compilation process:

sudo apt update
sudo apt install libmpfr-dev libgmp-dev
gcc -o phicalculator phicalculator.c -lmpfr -lgmp

Usage Notes

The only required input is the number of decimal digits you want the program to calculate. By default, it uses text output and the Fibonacci sequence method. However, you can also specify additional parameters:

./phicalculator <number of decimal places> --format=<text|json> --method=<fibonacci|cfraction|binet|newton>
./phicalculator 15
./phicalculator 15 --format=text --method=fibonacci
./phicalculator 15 --format=json --method=cfraction
./phicalculator 100 --format=json --method=binet
./phicalculator 100 --format=text --method=newton

// Text console output
Continued Fraction Phi to 15 decimal points: 1.618033988749894

// JSON console output
{"precision": "15", "method": "fibonacci", "phi": "1.618033988749894"}