2016 Update

This commit is contained in:
Tina Müller 2016-12-05 22:15:40 +01:00
parent 948b86eafa
commit dcf5d15da3
7965 changed files with 139854 additions and 31002 deletions

View file

@ -1,11 +1,19 @@
[[wp:Bernoulli number|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 <math>n</math>'th Bernoulli number is expressed as <span style="font-family:serif">'''B'''<sub>''n''</sub></span>.
[[wp:Bernoulli number|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&nbsp; n<sup>th</sup> &nbsp;Bernoulli number is expressed as&nbsp; '''B'''<sub>n</sub>.
<br>
;Task
* show the Bernoulli numbers <span style="font-family:serif">'''B'''<sub>0</sub></span> through <span style="font-family:serif">'''B'''<sub>60</sub></span>, suppressing all output of values which are equal to zero. (Other than <span style="font-family:serif">'''B'''<sub>1</sub></span>, all odd Bernoulli numbers have a value of 0 (zero).
* express the numbers as fractions (most are improper fractions).
** fractions should be reduced.
** index each number in some way so that it can be discerned which number is being displayed.
** align the solidi (<big>/</big>) if used (extra credit).
:* &nbsp; show the Bernoulli numbers &nbsp; '''B'''<sub>0</sub> &nbsp; through &nbsp; '''B'''<sub>60</sub>.
:* &nbsp; suppress the output of values which are equal to zero. (Other than &nbsp; '''B'''<sub>1</sub>&nbsp;, all ''odd'' Bernoulli numbers have a value of zero.)
:* &nbsp; express the Bernoulli numbers as fractions &nbsp;(most are improper fractions).
:* &nbsp; the fractions should be reduced.
:* &nbsp; index each number in some way so that it can be discerned which number is being displayed.
:* &nbsp; align the solidi &nbsp; (<big><b>/</b></big>) &nbsp; if used (extra credit).
;An algorithm
The AkiyamaTanigawa algorithm for the "second Bernoulli numbers" as taken from [[wp:Bernoulli_number#Algorithmic_description|wikipedia]] is as follows:
@ -21,3 +29,4 @@ The AkiyamaTanigawa algorithm for the "second Bernoulli numbers" as taken fro
* Sequence [http://oeis.org/A027642 A027642 Denominator of Bernoulli number B_n] on The On-Line Encyclopedia of Integer Sequences.
* Entry [http://mathworld.wolfram.com/BernoulliNumber.html Bernoulli number] on The Eric Weisstein's World of Mathematics (TM).
* Luschny's [http://luschny.de/math/zeta/The-Bernoulli-Manifesto.html The Bernoulli Manifesto] for a discussion on <math>B_1</math> = -&frac12; vs. +&frac12;.
<br><br>

View file

@ -0,0 +1,24 @@
ns test-project-intellij.core
(:gen-class))
(defn a-t [n]
" Used Akiyama-Tanigawa algorithm with a single loop rather than double nested loop "
" Clojure does fractional arithmetic automatically so that part is easy "
(loop [m 0
j m
A (vec (map #(/ 1 %) (range 1 (+ n 2))))] ; Prefil A(m) with 1/(m+1), for m = 1 to n
(cond ; Three way conditional allows single loop
(>= j 1) (recur m (dec j) (assoc A (dec j) (* j (- (nth A (dec j)) (nth A j))))) ; A[j-1] ← j×(A[j-1] - A[j]) ;
(< m n) (recur (inc m) (inc m) A) ; increment m, reset j = m
:else (nth A 0))))
(defn format-ans [ans]
" Formats answer so that '/' is aligned for all answers "
(if (= ans 1)
(format "%50d / %8d" 1 1)
(format "%50d / %8d" (numerator ans) (denominator ans))))
;; Generate a set of results for [0 1 2 4 ... 60]
(doseq [q (flatten [0 1 (range 2 62 2)])
:let [ans (a-t q)]]
(println q ":" (format-ans ans)))

View file

@ -0,0 +1,55 @@
defmodule Bernoulli do
defmodule Rational do
import Kernel, except: [div: 2]
defstruct numerator: 0, denominator: 1
def new(numerator, denominator\\1) do
sign = if numerator * denominator < 0, do: -1, else: 1
{numerator, denominator} = {abs(numerator), abs(denominator)}
gcd = gcd(numerator, denominator)
%Rational{numerator: sign * Kernel.div(numerator, gcd),
denominator: Kernel.div(denominator, gcd)}
end
def sub(a, b) do
new(a.numerator * b.denominator - b.numerator * a.denominator,
a.denominator * b.denominator)
end
def mul(a, b) when is_integer(a) do
new(a * b.numerator, b.denominator)
end
defp gcd(a,0), do: a
defp gcd(a,b), do: gcd(b, rem(a,b))
end
def numbers(n) do
Stream.transform(0..n, {}, fn m,acc ->
acc = Tuple.append(acc, Rational.new(1,m+1))
if m>0 do
new =
Enum.reduce(m..1, acc, fn j,ar ->
put_elem(ar, j-1, Rational.mul(j, Rational.sub(elem(ar,j-1), elem(ar,j))))
end)
{[elem(new,0)], new}
else
{[elem(acc,0)], acc}
end
end) |> Enum.to_list
end
def task(n \\ 61) do
b_nums = numbers(n)
width = Enum.map(b_nums, fn b -> b.numerator |> to_string |> String.length end)
|> Enum.max
format = 'B(~2w) = ~#{width}w / ~w~n'
Enum.with_index(b_nums)
|> Enum.each(fn {b,i} ->
if b.numerator != 0, do: :io.fwrite format, [i, b.numerator, b.denominator]
end)
end
end
Bernoulli.task

View file

@ -0,0 +1,35 @@
for a in Filtered(List([1 .. 60], n -> [n, Bernoulli(n)]), x -> x[2] <> 0) do
Print(a, "\n");
od;
[ 1, -1/2 ]
[ 2, 1/6 ]
[ 4, -1/30 ]
[ 6, 1/42 ]
[ 8, -1/30 ]
[ 10, 5/66 ]
[ 12, -691/2730 ]
[ 14, 7/6 ]
[ 16, -3617/510 ]
[ 18, 43867/798 ]
[ 20, -174611/330 ]
[ 22, 854513/138 ]
[ 24, -236364091/2730 ]
[ 26, 8553103/6 ]
[ 28, -23749461029/870 ]
[ 30, 8615841276005/14322 ]
[ 32, -7709321041217/510 ]
[ 34, 2577687858367/6 ]
[ 36, -26315271553053477373/1919190 ]
[ 38, 2929993913841559/6 ]
[ 40, -261082718496449122051/13530 ]
[ 42, 1520097643918070802691/1806 ]
[ 44, -27833269579301024235023/690 ]
[ 46, 596451111593912163277961/282 ]
[ 48, -5609403368997817686249127547/46410 ]
[ 50, 495057205241079648212477525/66 ]
[ 52, -801165718135489957347924991853/1590 ]
[ 54, 29149963634884862421418123812691/798 ]
[ 56, -2479392929313226753685415739663229/870 ]
[ 58, 84483613348880041862046775994036021/354 ]
[ 60, -1215233140483755572040304994079820246041491/56786730 ]

View file

@ -0,0 +1,22 @@
import org.apache.commons.math3.fraction.BigFraction;
public class BernoulliNumbers {
public static void main(String[] args) {
for (int n = 0; n <= 60; n++) {
BigFraction b = bernouilli(n);
if (!b.equals(BigFraction.ZERO))
System.out.printf("B(%-2d) = %-1s%n", n , b);
}
}
static BigFraction bernouilli(int n) {
BigFraction[] A = new BigFraction[n + 1];
for (int m = 0; m <= n; m++) {
A[m] = new BigFraction(1, (m + 1));
for (int j = m; j >= 1; j--)
A[j - 1] = (A[j - 1].subtract(A[j])).multiply(new BigFraction(j));
}
return A[0];
}
}

View file

@ -0,0 +1,26 @@
function bernoulli(n)
A = Vector{Rational{BigInt}}(n + 1)
for m = 0 : n
A[m + 1] = 1 // (m + 1)
for j = m : -1 : 1
A[j] = j * (A[j] - A[j + 1])
end
end
return A[1]
end
function display(n)
B = map(bernoulli, 0 : n)
pad = mapreduce(x -> ndigits(num(x)) + Int(x < 0), max, B)
argdigits = ndigits(n)
for i = 0 : n
if num(B[i + 1]) & 1 == 1
println(
"B(", lpad(i, argdigits), ") = ",
lpad(num(B[i + 1]), pad), " / ", den(B[i + 1])
)
end
end
end
display(60)

View file

@ -0,0 +1,22 @@
import org.apache.commons.math3.fraction.BigFraction
object Bernoulli {
operator fun invoke(n: Int) : BigFraction {
val A = Array(n + 1, init)
for (m in 0..n)
for (j in m downTo 1)
A[j - 1] = A[j - 1].subtract(A[j]).multiply(integers[j])
return A.first()
}
val max = 60
private val init = { m: Int -> BigFraction(1, m + 1) }
private val integers = Array(max + 1, { m: Int -> BigFraction(m) } )
}
fun main(args: Array<String>) {
for (n in 0..Bernoulli.max)
if (n % 2 == 0 || n == 1)
System.out.printf("B(%-2d) = %-1s%n", n, Bernoulli(n))
}

View file

@ -0,0 +1 @@
System.out.printf("B(%-2d) = %-1s%n", n, Bernoulli(n))

View file

@ -1,52 +1,52 @@
/*REXX program calculates a number of Bernoulli numbers expressed as fractions*/
parse arg N .; if N=='' then N=60 /*Not specified? Then use the default.*/
!.=0; w=max(length(N),4); Nw=N+N%5 /*used for aligning (output) fractions.*/
say 'B(n)' center('Bernoulli number expressed as a fraction', max(78-w, Nw))
say copies('',w) copies('', max(78-w, Nw + 2*w))
do #=0 to N /*process the numbers from 0 ──► N. */
b=bern(#); if b==0 then iterate /*calculate Bernoulli number, skip if 0*/
indent=max(0, nW-pos('/', b)) /*calculate alignment (indentation). */
say right(#,w) left('',indent) b /*display the indented Bernoulli number*/
end /*#*/ /* [↑] align the Bernoulli fractions. */
exit /*stick a fork in it, we're all done. */
/*──────────────────────────────────BERN subroutine───────────────────────────*/
bern: parse arg x /*obtain the subroutine argument. */
if x==0 then return '1/1' /*handle the special case of zero. */
if x==1 then return '-1/2' /* " " " " " one. */
if x//2 then return 0 /* " " " " " odds. */
/* [↓] process all numbers up to X, */
do j=2 to x by 2; jp=j+1; d=j+j /* ··· and set some shortcut vars.*/
if d>digits() then numeric digits d /*increase the decimal digits if needed*/
sn=1-j /*set the numerator. */
sd=2 /* " " denominator. */
do k=2 to j-1 by 2 /*calculate a SN/SD sequence. */
parse var @.k bn '/' ad /*get a previously calculated fraction.*/
an=comb(jp,k)*bn /*use COMBination for the next term. */
$lcm=lcm(sd,ad) /*use Least Common Denominator function*/
sn=$lcm%sd*sn; sd=$lcm /*calculate the current numerator. */
an=$lcm%ad*an; ad=$lcm /* " " next " */
sn=sn+an /* " " current " */
end /*k*/ /* [↑] calculate the SN/SD sequence.*/
sn=-sn /*adjust the sign for the numerator. */
sd=sd*jp /*calculate the denominator. */
if sn\==1 then do; _=gcd(sn, sd) /*get the Greatest Common Denominator.*/
sn=sn%_; sd=sd%_ /*reduce the numerator and denominator.*/
end /* [↑] done with the reduction(s). */
@.j=sn'/'sd /*save the result for the next round. */
end /*j*/ /* [↑] done calculating Bernoulli #'s.*/
/*REXX program calculates N number of Bernoulli numbers expressed as fractions. */
parse arg N .; if N=='' then N=60 /*Not specified? Then use the default.*/
!.=0; w=max(length(N),4); Nw=N+N%5 /*used for aligning (output) fractions.*/
say 'B(n)' center("Bernoulli number expressed as a fraction", max(78-w, Nw)) /*title*/
say copies('',w) copies("",max(78-w,Nw+2*w)) /*display 2nd line of title, separators*/
do #=0 to N /*process the numbers from 0 ──► N. */
b=bern(#); if b==0 then iterate /*calculate Bernoulli number, skip if 0*/
indent=max(0, nW-pos('/', b)) /*calculate the alignment (indentation)*/
say right(#, w) left('', indent) b /*display the indented Bernoulli number*/
end /*#*/ /* [↑] align the Bernoulli fractions. */
exit /*stick a fork in it, we're all done. */
/*──────────────────────────────────────────────────────────────────────────────────────*/
bern: parse arg x /*obtain the subroutine argument. */
if x==0 then return '1/1' /*handle the special case of zero. */
if x==1 then return '-1/2' /* " " " " " one. */
if x//2 then return 0 /* " " " " " odds. */
/* [↓] process all numbers up to X, */
do j=2 to x by 2; jp=j+1; d=j+j /* ··· and set some shortcut vars.*/
if d>digits() then numeric digits d /*increase the decimal digits if needed*/
sn=1-j /*set the numerator. */
sd=2 /* " " denominator. */
do k=2 to j-1 by 2 /*calculate a SN/SD sequence. */
parse var @.k bn '/' ad /*get a previously calculated fraction.*/
an=comb(jp,k)*bn /*use COMBination for the next term. */
$lcm=lcm(sd,ad) /*use Least Common Denominator function*/
sn=$lcm%sd*sn; sd=$lcm /*calculate the current numerator. */
an=$lcm%ad*an; ad=$lcm /* " " next " */
sn=sn+an /* " " current " */
end /*k*/ /* [↑] calculate the SN/SD sequence.*/
sn=-sn /*adjust the sign for the numerator. */
sd=sd*jp /*calculate the denominator. */
if sn\==1 then do; _=gcd(sn, sd) /*get the Greatest Common Denominator.*/
sn=sn%_; sd=sd%_ /*reduce the numerator and denominator.*/
end /* [↑] done with the reduction(s). */
@.j=sn'/'sd /*save the result for the next round. */
end /*j*/ /* [↑] done calculating Bernoulli #'s.*/
return sn'/'sd
/*────────────────────────────────────────────────────────────────────────────*/
return sn'/'sd
/*──────────────────────────────────────────────────────────────────────────────────────*/
comb: procedure expose !.; parse arg x,y; if x==y then return 1
if !.!c.x.y\==0 then return !.!c.x.y /*combination computed before?*/
if !.!c.x.y\==0 then return !.!c.x.y /*combination computed before?*/
if x-y<y then y=x-y; z=perm(x,y); do j=2 to y; z=z%j; end
!.!c.x.y=z; return z /*assign memoization; return. */
/*────────────────────────────────────────────────────────────────────────────*/
!.!c.x.y=z; return z /*assign memoization; return. */
/*──────────────────────────────────────────────────────────────────────────────────────*/
gcd: procedure; parse arg x,y; x=abs(x)
do until y==0; parse value x//y y with y x; end; return x
/*────────────────────────────────────────────────────────────────────────────*/
/*──────────────────────────────────────────────────────────────────────────────────────*/
lcm: procedure; parse arg x,y; x=abs(x); return x*y/gcd(x,y)
/*────────────────────────────────────────────────────────────────────────────*/
/*──────────────────────────────────────────────────────────────────────────────────────*/
perm: procedure expose !.; parse arg x,y; z=1
if !.!p.x.y\==0 then return !.!p.x.y /*permutation computed before?*/
do j=x-y+1 to x; z=z*j; end; !.!p.x.y=z; return z
if !.!p.x.y\==0 then return !.!p.x.y /*permutation computed before?*/
do j=x-y+1 to x; z=z*j; end; !.!p.x.y=z; return z

View file

@ -0,0 +1,149 @@
// 2.5 implementations presented here: naive, optimized, and an iterator using
// the optimized function. The speeds vary significantly: relative
// speeds of optimized:iterator:naive implementations is 625:25:1.
#![feature(test)]
extern crate num;
extern crate test;
use num::bigint::{BigInt, ToBigInt};
use num::rational::{BigRational};
use std::cmp::max;
use std::env;
use std::ops::{Mul, Sub};
use std::process;
struct Bn {
value: BigRational,
index: i32
}
struct Context {
bigone_const: BigInt,
a: Vec<BigRational>,
index: i32 // Counter for iterator implementation
}
impl Context {
pub fn new() -> Context {
let bigone = 1.to_bigint().unwrap();
let a_vec: Vec<BigRational> = vec![];
Context {
bigone_const: bigone,
a: a_vec,
index: -1
}
}
}
impl Iterator for Context {
type Item = Bn;
fn next(&mut self) -> Option<Bn> {
self.index += 1;
Some(Bn { value: bernoulli(self.index as usize, self), index: self.index })
}
}
fn help() {
println!("Usage: bernoulli_numbers <up_to>");
}
fn main() {
let args: Vec<String> = env::args().collect();
let mut up_to: usize = 60;
match args.len() {
1 => {},
2 => {
up_to = args[1].parse::<usize>().unwrap();
},
_ => {
help();
process::exit(0);
}
}
let context = Context::new();
// Collect the solutions by using the Context iterator
// (this is not as fast as calling the optimized function directly).
let res = context.take(up_to + 1).collect::<Vec<_>>();
let width = res.iter().fold(0, |a, r| max(a, r.value.numer().to_string().len()));
for r in res.iter().filter(|r| r.index % 2 == 0) {
println!("B({:>2}) = {:>2$} / {denom}", r.index, r.value.numer(), width,
denom = r.value.denom());
}
}
// Implementation with no reused calculations.
fn _bernoulli_naive(n: usize, c: &mut Context) -> BigRational {
for m in 0..n + 1 {
c.a.push(BigRational::new(c.bigone_const.clone(), (m + 1).to_bigint().unwrap()));
for j in (1..m + 1).rev() {
c.a[j - 1] = (c.a[j - 1].clone().sub(c.a[j].clone())).mul(
BigRational::new(j.to_bigint().unwrap(), c.bigone_const.clone())
);
}
}
c.a[0].reduced()
}
// Implementation with reused calculations (does not require sequential calls).
fn bernoulli(n: usize, c: &mut Context) -> BigRational {
for i in 0..n + 1 {
if i >= c.a.len() {
c.a.push(BigRational::new(c.bigone_const.clone(), (i + 1).to_bigint().unwrap()));
for j in (1..i + 1).rev() {
c.a[j - 1] = (c.a[j - 1].clone().sub(c.a[j].clone())).mul(
BigRational::new(j.to_bigint().unwrap(), c.bigone_const.clone())
);
}
}
}
c.a[0].reduced()
}
#[cfg(test)]
mod tests {
use super::{Bn, Context, bernoulli, _bernoulli_naive};
use num::rational::{BigRational};
use std::str::FromStr;
use test::Bencher;
// [tests elided]
#[bench]
fn bench_bernoulli_naive(b: &mut Bencher) {
let mut context = Context::new();
b.iter(|| {
let mut res: Vec<Bn> = vec![];
for n in 0..30 + 1 {
let b = _bernoulli_naive(n, &mut context);
res.push(Bn { value:b.clone(), index: n as i32});
}
});
}
#[bench]
fn bench_bernoulli(b: &mut Bencher) {
let mut context = Context::new();
b.iter(|| {
let mut res: Vec<Bn> = vec![];
for n in 0..30 + 1 {
let b = bernoulli(n, &mut context);
res.push(Bn { value:b.clone(), index: n as i32});
}
});
}
#[bench]
fn bench_bernoulli_iter(b: &mut Bencher) {
b.iter(|| {
let context = Context::new();
let _res = context.take(30 + 1).collect::<Vec<_>>();
});
}
}

View file

@ -0,0 +1,49 @@
/** Roll our own pared-down BigFraction class just for these Bernoulli Numbers */
case class BFraction( numerator:BigInt, denominator:BigInt ) {
require( denominator != BigInt(0), "Denominator cannot be zero" )
val gcd = numerator.gcd(denominator)
val num = numerator / gcd
val den = denominator / gcd
def unary_- = BFraction(-num, den)
def -( that:BFraction ) = that match {
case f if f.num == BigInt(0) => this
case f if f.den == this.den => BFraction(this.num - f.num, this.den)
case f => BFraction(((this.num * f.den) - (f.num * this.den)), this.den * f.den )
}
def *( that:Int ) = BFraction( num * that, den )
override def toString = num + " / " + den
}
def bernoulliB( n:Int ) : BFraction = {
val aa : Array[BFraction] = Array.ofDim(n+1)
for( m <- 0 to n ) {
aa(m) = BFraction(1,(m+1))
for( n <- m to 1 by -1 ) {
aa(n-1) = (aa(n-1) - aa(n)) * n
}
}
aa(0)
}
assert( {val b12 = bernoulliB(12); b12.num == -691 && b12.den == 2730 } )
val r = for( n <- 0 to 60; b = bernoulliB(n) if b.num != 0 ) yield (n, b)
val numeratorSize = r.map(_._2.num.toString.length).max
// Print the results
r foreach{ case (i,b) => {
val label = f"b($i)"
val num = (" " * (numeratorSize - b.num.toString.length)) + b.num
println( f"$label%-6s $num / ${b.den}" )
}}