How to resolve the algorithm Bernoulli numbers step by step in the Haskell programming language

Published on 7 June 2024 03:52 AM

How to resolve the algorithm Bernoulli numbers step by step in the Haskell programming language

Table of Contents

Problem Statement

Bernoulli numbers are used in some series expansions of several functions   (trigonometric, hyperbolic, gamma, etc.),   and are extremely important in number theory and analysis. Note that there are two definitions of Bernoulli numbers;   this task will be using the modern usage   (as per   The National Institute of Standards and Technology convention). The   nth   Bernoulli number is expressed as   Bn.

The Akiyama–Tanigawa algorithm for the "second Bernoulli numbers" as taken from wikipedia is as follows:

Let's start with the solution:

Step by Step solution about How to resolve the algorithm Bernoulli numbers step by step in the Haskell programming language

This Haskell code generates and prints the Bernoulli numbers up to a specified index (60 by default). Bernoulli numbers are a sequence of rational numbers that occur naturally in many mathematical contexts.

Here's a breakdown of the code:

  1. Importing Modules:

    import Data.Ratio
    import System.Environment

    These modules provide functions for working with rational numbers and for interacting with the command line.

  2. main Function:

    main = getArgs >>= printM . defaultArg
     where
       defaultArg as =
         if null as
           then 60
           else read (head as)

    The main function is the entry point of the program. It uses the getArgs function to retrieve command-line arguments. If no arguments are provided, it defaults to generating the first 60 Bernoulli numbers. If arguments are provided, it reads the first argument as an integer and uses that as the upper bound for generating the numbers.

  3. printM Function:

    printM m =
     mapM_ (putStrLn . printP) .
     takeWhile ((<= m) . fst) . filter (\(_, b) -> b /= 0 % 1) . zip [0 ..] $
     bernoullis

    The printM function takes a rational number m and prints the Bernoulli numbers up to that index. It applies the printP function to each Bernoulli number and uses mapM_ to print them one by one.

  4. printP Function:

    printP (i, r) =
     "B(" ++ show i ++ ") = " ++ show (numerator r) ++ "/" ++ show (denominator r)

    The printP function takes a pair of a number i and a rational number r and prints it in a user-friendly format. It displays the Bernoulli number B(i) as a fraction with numerator and denominator.

  5. bernoullis Function:

    bernoullis = map head . iterate (ulli 1) . map berno $ enumFrom 0
     where
       berno i = 1 % (i + 1)
       ulli _ [_] = []
       ulli i (x:y:xs) = (i % 1) * (x - y) : ulli (i + 1) (y : xs)

    The bernoullis function generates the Bernoulli numbers using a recursive approach. It starts with the initial Bernoulli number B(0) = 1 and then calculates subsequent numbers using a recurrence relation. The berno function provides the initial Bernoulli numbers, and the ulli function calculates the differences between consecutive Bernoulli numbers.

  6. Improved Bernoulli Number Generation (with faulhaber):

    This version of the code provides an alternative method for generating Bernoulli numbers using the Faulhaber triangle. It defines the bernouillis function as follows:

    bernouillis :: Integer -> [Rational]
    bernouillis =
     fmap head
       . tail
       . scanl faulhaber []
       . enumFromTo 0

    The faulhaber function constructs the Faulhaber triangle and uses it to generate Bernoulli numbers. It iteratively calculates the differences between consecutive rows of the triangle.

  7. faulhaber Function:

    faulhaber :: [Ratio Integer] -> Integer -> [Ratio Integer]
    faulhaber rs n =
     (:) =<< (-) 1 . sum $
       zipWith ((*) . (n %)) [2 ..] rs

    The faulhaber function takes a list of rational numbers rs and an integer n and generates the next row of the Faulhaber triangle. It multiplies each element of rs by n % and subtracts the sum from 1.

  8. Testing and Formatting:

    The code includes a main function for testing and formatting the output. It generates the first 60 Bernoulli numbers, calculates their numerators' lengths, and prints the results in a table format.

    The fTable function is used for formatting the table, while showRatio and rjust are helper functions for displaying rational numbers and right-justifying strings.

Overall, this code demonstrates two different approaches for generating Bernoulli numbers in Haskell and provides a user-friendly interface for viewing the results.

Source code in the haskell programming language

import Data.Ratio
import System.Environment

main = getArgs >>= printM . defaultArg
  where
    defaultArg as =
      if null as
        then 60
        else read (head as)

printM m =
  mapM_ (putStrLn . printP) .
  takeWhile ((<= m) . fst) . filter (\(_, b) -> b /= 0 % 1) . zip [0 ..] $
  bernoullis

printP (i, r) =
  "B(" ++ show i ++ ") = " ++ show (numerator r) ++ "/" ++ show (denominator r)

bernoullis = map head . iterate (ulli 1) . map berno $ enumFrom 0
  where
    berno i = 1 % (i + 1)
    ulli _ [_] = []
    ulli i (x:y:xs) = (i % 1) * (x - y) : ulli (i + 1) (y : xs)


import Data.Bool (bool)
import Data.Ratio (Ratio, denominator, numerator, (%))

-------------------- BERNOULLI NUMBERS -------------------

bernouillis :: Integer -> [Rational]
bernouillis =
  fmap head
    . tail
    . scanl faulhaber []
    . enumFromTo 0

faulhaber :: [Ratio Integer] -> Integer -> [Ratio Integer]
faulhaber rs n =
  (:) =<< (-) 1 . sum $
    zipWith ((*) . (n %)) [2 ..] rs

--------------------------- TEST -------------------------
main :: IO ()
main = do
  let xs = bernouillis 60
      w = length $ show (numerator (last xs))
  putStrLn $
    fTable
      "Bernouillis from Faulhaber triangle:\n"
      (show . fst)
      (showRatio w . snd)
      id
      (filter ((0 /=) . snd) $ zip [0 ..] xs)

------------------------ FORMATTING ----------------------
fTable ::
  String ->
  (a -> String) ->
  (b -> String) ->
  (a -> b) ->
  [a] ->
  String
fTable s xShow fxShow f xs =
  let w = maximum (length . xShow <$> xs)
   in unlines $
        s :
        fmap
          ( ((<>) . rjust w ' ' . xShow)
              <*> ((" -> " <>) . fxShow . f)
          )
          xs

showRatio :: Int -> Rational -> String
showRatio w r =
  let d = denominator r
   in rjust w ' ' $ show (numerator r)
        <> bool [] (" / " <> show d) (1 /= d)

rjust :: Int -> a -> [a] -> [a]
rjust n c = drop . length <*> (replicate n c <>)


  

You may also check:How to resolve the algorithm File size step by step in the Pike programming language
You may also check:How to resolve the algorithm 15 puzzle solver step by step in the Phix programming language
You may also check:How to resolve the algorithm Old lady swallowed a fly step by step in the Perl programming language
You may also check:How to resolve the algorithm Text processing/Max licenses in use step by step in the jq programming language
You may also check:How to resolve the algorithm Additive primes step by step in the Lambdatalk programming language