{-
	Copyright (C) 2011 Dr. Alistair Ward

	This program is free software: you can redistribute it and/or modify
	it under the terms of the GNU General Public License as published by
	the Free Software Foundation, either version 3 of the License, or
	(at your option) any later version.

	This program is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
	GNU General Public License for more details.

	You should have received a copy of the GNU General Public License
	along with this program.  If not, see <http://www.gnu.org/licenses/>.
-}
{- |
 [@AUTHOR@]	Dr. Alistair Ward

 [@DESCRIPTION@]

	* Implements a /Bailey-Borwein-Plouffe/ formula; <http://mathworld.wolfram.com/PiFormulas.html>

	* Surprisingly, because of the huge size of the 'Rational' quantities,
	it is a /single/ call to @Factory.Math.Summation.sum'@, rather than the calculation of the many terms in the series, which is the performance-bottleneck.
-}

module Factory.Math.Implementations.Pi.BBP.Implementation(
-- * Functions
	openR
) where

import			Data.Ratio((%))
import qualified	Factory.Math.Implementations.Pi.BBP.Series	as Math.Implementations.Pi.BBP.Series
import qualified	Factory.Math.Precision				as Math.Precision
import qualified	Factory.Math.Summation				as Math.Summation

-- | Returns /Pi/, accurate to the specified number of decimal digits.
openR
	:: Math.Implementations.Pi.BBP.Series.Series	-- ^ This /Pi/-algorithm is parameterised by the type of other algorithms to use.
	-> Math.Precision.DecimalDigits			-- ^ The number of decimal digits required.
	-> Rational
openR Math.Implementations.Pi.BBP.Series.MkSeries {
	Math.Implementations.Pi.BBP.Series.numerators		= numerators,
	Math.Implementations.Pi.BBP.Series.getDenominators	= getDenominators,
	Math.Implementations.Pi.BBP.Series.seriesScalingFactor	= seriesScalingFactor,
	Math.Implementations.Pi.BBP.Series.base			= base
} decimalDigits		= (seriesScalingFactor *) . Math.Summation.sum' 8 . take (
	Math.Precision.getTermsRequired (
		recip . fromIntegral $ abs {-potentially negative-} base	-- The convergence-rate.
	) decimalDigits
 ) . zipWith (*) (
	iterate (/ fromIntegral base) 1	-- Generate the scaling-ratio, between successive terms.
 ) $ map (
	sum . zipWith (%) numerators . getDenominators
 ) [0 ..]