{-# LINE 1 "src/Data/Number/Flint/Bernoulli/FFI.hsc" #-} {-| module : Data.Number.Flint.Bernoulli.FFI copyright : (c) 2022 Hartmut Monien license : GNU GPL, version 2 or above (see LICENSE) maintainer : hmonien@uni-bonn.de -} module Data.Number.Flint.Bernoulli.FFI ( -- * Support for Bernoulli numbers -- * Generation of Bernoulli numbers BernoulliRev (..) , CBernoulliRev (..) , newBernoulliRev , withBernoulliRev , withNewBernoulliRev , bernoulli_rev_init , bernoulli_rev_next , bernoulli_rev_clear , bernoulli_fmpq_vec_no_cache -- * Caching , bernoulli_cache_compute -- * Bounding , bernoulli_bound_2exp_si -- * Isolated Bernoulli numbers , bernoulli_mod_p_harvey , _bernoulli_fmpq_ui_zeta , _bernoulli_fmpq_ui ) where -- Support for Bernoulli numbers ----------------------------------------------- import Foreign.Ptr import Foreign.ForeignPtr import Foreign.C.Types import Foreign.Storable import Data.Number.Flint.Flint import Data.Number.Flint.Fmpz import Data.Number.Flint.Fmpq import Data.Number.Flint.Arb.Types import Data.Number.Flint.Acb.Types -- bernoulli_rev_t ------------------------------------------------------------- data BernoulliRev = BernoulliRev {-# UNPACK #-} !(ForeignPtr CBernoulliRev) type CBernoulliRev = CFlint BernoulliRev instance Storable CBernoulliRev where sizeOf :: CBernoulliRev -> Int sizeOf CBernoulliRev _ = (Int 144) {-# LINE 52 "src/Data/Number/Flint/Bernoulli/FFI.hsc" #-} alignment _ = 8 {-# LINE 53 "src/Data/Number/Flint/Bernoulli/FFI.hsc" #-} peek = error "CBernoulliRev.peek: not implemented." poke :: Ptr CBernoulliRev -> CBernoulliRev -> IO () poke = forall a. HasCallStack => [Char] -> a error [Char] "CBernoulliRev.poke: not implemented." newBernoulliRev :: CULong -> IO BernoulliRev newBernoulliRev CULong n = do ForeignPtr CBernoulliRev x <- forall a. Storable a => IO (ForeignPtr a) mallocForeignPtr forall a b. ForeignPtr a -> (Ptr a -> IO b) -> IO b withForeignPtr ForeignPtr CBernoulliRev x forall a b. (a -> b) -> a -> b $ \Ptr CBernoulliRev x -> do Ptr CBernoulliRev -> CULong -> IO () bernoulli_rev_init Ptr CBernoulliRev x CULong n forall a. FinalizerPtr a -> ForeignPtr a -> IO () addForeignPtrFinalizer FunPtr (Ptr CBernoulliRev -> IO ()) p_bernoulli_rev_clear ForeignPtr CBernoulliRev x forall (m :: * -> *) a. Monad m => a -> m a return forall a b. (a -> b) -> a -> b $ ForeignPtr CBernoulliRev -> BernoulliRev BernoulliRev ForeignPtr CBernoulliRev x withBernoulliRev :: BernoulliRev -> (Ptr CBernoulliRev -> IO a) -> IO (BernoulliRev, a) withBernoulliRev (BernoulliRev ForeignPtr CBernoulliRev x) Ptr CBernoulliRev -> IO a f = do forall a b. ForeignPtr a -> (Ptr a -> IO b) -> IO b withForeignPtr ForeignPtr CBernoulliRev x forall a b. (a -> b) -> a -> b $ \Ptr CBernoulliRev xp -> (ForeignPtr CBernoulliRev -> BernoulliRev BernoulliRev ForeignPtr CBernoulliRev x,) forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b <$> Ptr CBernoulliRev -> IO a f Ptr CBernoulliRev xp withNewBernoulliRev :: CULong -> (Ptr CBernoulliRev -> IO a) -> IO (BernoulliRev, a) withNewBernoulliRev CULong n Ptr CBernoulliRev -> IO a f = do BernoulliRev x <- CULong -> IO BernoulliRev newBernoulliRev CULong n forall {a}. BernoulliRev -> (Ptr CBernoulliRev -> IO a) -> IO (BernoulliRev, a) withBernoulliRev BernoulliRev x Ptr CBernoulliRev -> IO a f -- Generation of Bernoulli numbers --------------------------------------------- -- | /bernoulli_rev_init/ /iter/ /n/ -- -- Initializes the iterator /iter/. The first Bernoulli number to be -- generated by calling @bernoulli_rev_next@ is \(B_n\). It is assumed that -- \(n\) is even. foreign import ccall "bernoulli.h bernoulli_rev_init" bernoulli_rev_init :: Ptr CBernoulliRev -> CULong -> IO () -- | /bernoulli_rev_next/ /numer/ /denom/ /iter/ -- -- Sets /numer/ and /denom/ to the exact, reduced numerator and denominator -- of the Bernoulli number \(B_k\) and advances the state of /iter/ so that -- the next invocation generates \(B_{k-2}\). foreign import ccall "bernoulli.h bernoulli_rev_next" bernoulli_rev_next :: Ptr CFmpz -> Ptr CFmpz -> Ptr CBernoulliRev -> IO () -- | /bernoulli_rev_clear/ /iter/ -- -- Frees all memory allocated internally by /iter/. foreign import ccall "bernoulli.h bernoulli_rev_clear" bernoulli_rev_clear :: Ptr CBernoulliRev -> IO () foreign import ccall "bernoulli.h &bernoulli_rev_clear" p_bernoulli_rev_clear :: FunPtr (Ptr CBernoulliRev -> IO ()) -- | /bernoulli_fmpq_vec_no_cache/ /res/ /a/ /num/ -- -- Writes /num/ consecutive Bernoulli numbers to /res/ starting with -- \(B_a\). This function is not currently optimized for a small count -- /num/. The entries are not read from or written to the Bernoulli number -- cache; if retrieving a vector of Bernoulli numbers is needed more than -- once, use @bernoulli_cache_compute@ followed by @bernoulli_fmpq_ui@ -- instead. -- -- This function is a wrapper for the /rev/ iterators. It can use multiple -- threads internally. foreign import ccall "bernoulli.h bernoulli_fmpq_vec_no_cache" bernoulli_fmpq_vec_no_cache :: Ptr CFmpq -> CULong -> CLong -> IO () -- Caching --------------------------------------------------------------------- -- | /bernoulli_cache_compute/ /n/ -- -- Makes sure that the Bernoulli numbers up to at least \(B_{n-1}\) are -- cached. Calling @flint_cleanup()@ frees the cache. -- -- The cache is extended by calling @bernoulli_fmpq_vec_no_cache@ -- internally. foreign import ccall "bernoulli.h bernoulli_cache_compute" bernoulli_cache_compute :: CLong -> IO () -- Bounding -------------------------------------------------------------------- -- | /bernoulli_bound_2exp_si/ /n/ -- -- Returns an integer \(b\) such that \(|B_n| \le 2^b\). Uses a lookup -- table for small \(n\), and for larger \(n\) uses the inequality -- \(|B_n| < 4 n! / (2 \pi)^n < 4 (n+1)^{n+1} e^{-n} / (2 \pi)^n\). Uses -- integer arithmetic throughout, with the bound for the logarithm being -- looked up from a table. If \(|B_n| = 0\), returns /LONG_MIN/. Otherwise, -- the returned exponent \(b\) is never more than one percent larger than -- the true magnitude. -- -- This function is intended for use when \(n\) small enough that one might -- comfortably compute \(B_n\) exactly. It aborts if \(n\) is so large that -- internal overflow occurs. foreign import ccall "bernoulli.h bernoulli_bound_2exp_si" bernoulli_bound_2exp_si :: CULong -> IO CLong -- Isolated Bernoulli numbers -------------------------------------------------- -- | /bernoulli_mod_p_harvey/ /n/ /p/ -- -- Returns the \(B_n\) modulo the prime number /p/, computed using -- Harvey\'s algorithm < [Har2010]>. The running time is linear in /p/. If -- /p/ divides the numerator of \(B_n\), /UWORD_MAX/ is returned as an -- error code. foreign import ccall "bernoulli.h bernoulli_mod_p_harvey" bernoulli_mod_p_harvey :: CULong -> CULong -> IO CULong -- | /_bernoulli_fmpq_ui_zeta/ /num/ /den/ /n/ -- -- Sets /num/ and /den/ to the reduced numerator and denominator of the -- Bernoulli number \(B_n\). -- -- The /zeta/ version computes the denominator \(d\) using the von -- Staudt-Clausen theorem, numerically approximates \(B_n\) using -- @arb_bernoulli_ui_zeta@, and then rounds \(d B_n\) to the correct -- numerator. -- -- The /multi_mod/ version reconstructs \(B_n\) by computing the high bits -- via the Riemann zeta function and the low bits via Harvey\'s -- multimodular algorithm. The tuning parameter /alpha/ should be a -- fraction between 0 and 1 controlling the number of bits to compute by -- the multimodular algorithm. If set to a negative number, a default value -- will be used. foreign import ccall "bernoulli.h _bernoulli_fmpq_ui_zeta" _bernoulli_fmpq_ui_zeta :: Ptr CFmpz -> Ptr CFmpz -> CULong -> IO () -- | /_bernoulli_fmpq_ui/ /num/ /den/ /n/ -- -- Computes the Bernoulli number \(B_n\) as an exact fraction, for an -- isolated integer \(n\). This function reads \(B_n\) from the global -- cache if the number is already cached, but does not automatically extend -- the cache by itself. foreign import ccall "bernoulli.h _bernoulli_fmpq_ui" _bernoulli_fmpq_ui :: Ptr CFmpz -> Ptr CFmpz -> CULong -> IO ()