--- title: "Evaluating the Gauss hypergeometric function in Ruby" author: "Stéphane Laurent" date: "13/07/2015" output: html_document --- ```{r, include=FALSE, memo=TRUE} library(knitr) source("./assets/knitrEngines/ruby00.R") ``` I have previously shown [how to efficiently evaluate the Gauss hypergeometric function using arithmetic on large integers](http://stla.github.io/stlapblog/posts/BS_F21_v3.html), with the help of the binary splitting algorithm. I have now written the binary splitting algorithm in Ruby. This is rather straightforward in Ruby because it automatically converts integers to the `Bignum` large integer class when needed. Moreover, numeric variables have a `to_r` method to convert to a rational number (`Rational` class). One can even directly apply the methods `numerator` and `denominator` to extract the numerator and the denominator of the rational approximation. ```{r, engine='RUBY', memo=TRUE} def hypergeo(a,b,c,x,m=7) p = x.numerator q = x.denominator a1 = a.numerator a2 = a.denominator b1 = b.numerator b2 = b.denominator c1 = c.numerator c2 = c.denominator n=2**m indexes = (1..n) delta = indexes.collect{ |i| c2 * (a1 + (i - 1) * a2) * (b1 + (i - 1) * b2) * p } alpha = delta beta = indexes.collect{ |i| a2 * b2 * i * (c1 + (i - 1) * c2) * q } j = 1 l = n while j < n do odd = (2..l).step(2) even = (1..l-1).step(2) alpha = [[odd.map{|i| beta[i-1]}, even.map{|i| alpha[i-1]}].transpose.map{|x| x.reduce(:*)}, [odd.map{|i| alpha[i-1]}, even.map{|i| delta[i-1]}].transpose.map{|x| x.reduce(:*)}].transpose.map{|x| x.reduce(:+)} beta = [odd.map{|i| beta[i-1]}, even.map{|i| beta[i-1]}].transpose.map{|x| x.reduce(:*)} delta = [odd.map{|i| delta[i-1]}, even.map{|i| delta[i-1]}].transpose.map{|x| x.reduce(:*)} l = l/2 j = 2*j end Rational(alpha[0],beta[0]).to_f + 1 end ``` It seems to work fine: ```{r, engine='RUBY', use.memo=TRUE} puts hypergeo(20.5, 11.92, 19, 0.5, 7) ```
```{r, echo=FALSE} rm(list=ls()) knit_exit() ```