Path: blob/master/src/sage/rings/bernmm/bernmm-test.cpp
8820 views
/*1bernmm-test.cpp: test module23Copyright (C) 2008, 2009, David Harvey45This file is part of the bernmm package (version 1.1).67bernmm is released under a BSD-style license. See the README file in8the source distribution for details.9*/1011#include <iostream>12#include <NTL/ZZ.h>13#include <gmp.h>14#include "bern_modp_util.h"15#include "bern_modp.h"16#include "bern_rat.h"171819NTL_CLIENT;202122using namespace bernmm;23using namespace std;242526/*27Computes B_0, B_1, ..., B_{n-1} using naive algorithm, writes them to res.28*/29void bern_naive(mpq_t* res, long n)30{31mpq_t t, u;32mpq_init(t);33mpq_init(u);3435// compute res[j] = B_j / j! for 0 <= j < n36if (n > 0)37mpq_set_si(res[0], 1, 1);3839for (long j = 1; j < n; j++)40{41mpq_set_si(res[j], 0, 1);42mpq_set_ui(t, 1, 1);43for (long k = 0; k < j; k++)44{45mpz_mul_ui(mpq_denref(t), mpq_denref(t), k + 2);46mpq_mul(u, res[j - 1 - k], t);47mpq_sub(res[j], res[j], u);48}49}5051// multiply through by j! for 0 <= j < n52mpq_set_ui(t, 1, 1);53for (long j = 2; j < n; j++)54{55mpz_mul_ui(mpq_numref(t), mpq_numref(t), j);56mpq_mul(res[j], res[j], t);57}5859mpq_clear(u);60mpq_clear(t);61}626364/*65Tests _bern_modp_powg() for a given p and k by comparing against the66rational number B_k (must be supplied in b).6768Returns 1 on success.69*/70int testcase__bern_modp_powg(long p, long k, mpq_t b)71{72double pinv = 1 / ((double) p);7374// compute B_k mod p using _bern_modp_powg()75long x = _bern_modp_powg(p, pinv, k);76x = MulMod(x, k, p, pinv);7778// compute B_k mod p from rational B_k79long y = mpz_fdiv_ui(mpq_numref(b), p);80long z = mpz_fdiv_ui(mpq_denref(b), p);81return y == MulMod(z, x, p, pinv);82}83848586/*87Tests _bern_modp_powg() by comparing against naive computation of B_k88(as a rational) for a range of small p and k.8990Returns 1 on success.91*/92int test__bern_modp_powg()93{94int success = 1;9596const long MAX = 300;97mpq_t bern[MAX];9899// compute B_k's as rational numbers using naive algorithm100for (long i = 0; i < MAX; i++)101mpq_init(bern[i]);102bern_naive(bern, MAX);103104// try a range of k's105for (long k = 2; k < MAX && success; k += 2)106{107// try a range of small p's108for (long p = k + 3; p < 2*MAX && success; p += 2)109{110if (!ProbPrime(p))111continue;112success = success && testcase__bern_modp_powg(p, k, bern[k]);113}114115// try a single larger p116success = success && testcase__bern_modp_powg(1000003, k, bern[k]);117}118119// if we're on a 32-bit machine, try a single example with p right near120// NTL's boundary (this is infeasible on a 64-bit machine)121if (NTL_SP_NBITS <= 32)122{123long p = NTL_SP_BOUND - 1;124while (!ProbPrime(p))125p--;126127long k = (MAX/2)*2 - 2;128success = success && testcase__bern_modp_powg(p, k, bern[k]);129}130131for (long i = 0; i < MAX; i++)132mpq_clear(bern[i]);133134return success;135}136137138139/*140Tests _bern_modp_pow2() for a given p and k by comparing against result141from _bern_modp_powg().142143Returns 1 on success.144145If 2^k = 1 mod p, then _bern_modp_pow2() won't work, so it just returns 1.146*/147int testcase__bern_modp_pow2(long p, long k)148{149double pinv = 1 / ((double) p);150151if (PowerMod(2, k, p, pinv) == 1)152return 1;153154long x = _bern_modp_powg(p, pinv, k);155long y = _bern_modp_pow2(p, pinv, k);156157return x == y;158}159160161162/*163Tests _bern_modp_pow2() by comparing against _bern_modp_powg() for164a range of p and k.165166Returns 1 on success.167*/168int test__bern_modp_pow2()169{170int success = 1;171172// exhaustive comparison over some small p and k173for (long p = 5; p < 2000 && success; p += 2)174{175if (!ProbPrime(p))176continue;177178for (long k = 2; k <= p - 3 && success; k += 2)179success = success && testcase__bern_modp_pow2(p, k);180}181182// a few larger values of p183for (long p = 1000000; p < 1030000; p++)184{185if (!ProbPrime(p))186continue;187188long k = 2 * (rand() % ((p-3)/2)) + 2;189success = success && testcase__bern_modp_pow2(p, k);190}191192// if we're on a 32-bit machine, try a single example with p right near193// NTL's boundary (this is infeasible on a 64-bit machine)194if (NTL_SP_NBITS <= 32)195{196long p = NTL_SP_BOUND - 1;197while (!ProbPrime(p))198p--;199success = success & testcase__bern_modp_pow2(p, 10);200}201202// try a few just below the REDC barrier203if (ULONG_BITS == 32)204{205long boundary = 1L << (ULONG_BITS/2 - 1);206for (long p = boundary - 1000; p < boundary && success; p++)207{208if (ProbPrime(p))209{210for (long trial = 0; trial < 1000 && success; trial++)211{212long k = 2 * (rand() % ((p-3)/2)) + 2;213success = success && testcase__bern_modp_pow2(p, k);214}215}216}217}218else219{220// on a 64-bit machine, only try one, since these are huge!221long p = 1L << (ULONG_BITS/2 - 1);222while (!ProbPrime(p))223p--;224success = success && testcase__bern_modp_pow2(p, 10);225}226227return success;228}229230231/*232Tests bern_rat() by comparing against the naive algorithm for several small233k, and testing against bern_modp() for a couple of larger k.234235Returns 1 on success.236*/237int test_bern_rat()238{239int success = 1;240241const long MAX = 300;242mpq_t bern[MAX];243244// compute B_k's as rational numbers using naive algorithm245for (long i = 0; i < MAX; i++)246mpq_init(bern[i]);247bern_naive(bern, MAX);248249mpq_t x;250mpq_init(x);251252// exhaustive test for small k253for (long k = 0; k < MAX && success; k++)254{255bern_rat(x, k, 4); // try with 4 threads just for fun256success = success && mpq_equal(x, bern[k]);257}258259// try a few larger k260for (long i = 0; i < 50 && success; i++)261{262long k = ((random() % 20000) / 2) * 2;263bern_rat(x, k, 4);264265// compare with modular information266long p = 1000003;267long num = mpz_fdiv_ui(mpq_numref(x), p);268long den = mpz_fdiv_ui(mpq_denref(x), p);269success = success && (MulMod(bern_modp(p, k), den, p) == num);270}271272mpq_clear(x);273for (long i = 0; i < MAX; i++)274mpq_clear(bern[i]);275276return success;277}278279280void report(int success)281{282if (success)283cout << "ok" << endl;284else285{286cout << "failed!" << endl;287abort();288}289}290291292int main(int argc, char* argv[])293{294if (argc == 1)295{296cout << "bernmm test module" << endl;297cout << endl;298cout << " bernmm-test --test" << endl;299cout << " runs test suite" << endl;300cout << " bernmm-test --rational <k> <threads>" << endl;301cout << " computes B_k with <threads> threads" << endl;302cout << " bernmm-test --modular <p> <k>" << endl;303cout << " computes B_k mod p" << endl;304return 0;305}306307if (!strcmp(argv[1], "--test"))308{309cout << "testing _bern_modp_powg()... " << flush;310report(test__bern_modp_powg());311312cout << "testing _bern_modp_pow2()... " << flush;313report(test__bern_modp_pow2());314315cout << "testing bern_rat()... " << flush;316report(test_bern_rat());317}318else if (!strcmp(argv[1], "--rational"))319{320if (argc <= 3)321{322cout << "not enough arguments" << endl;323return 0;324}325long k = atol(argv[2]);326long threads = atol(argv[3]);327mpq_t r;328mpq_init(r);329bern_rat(r, k, threads);330gmp_printf("%Zd/%Zd\n", mpq_numref(r), mpq_denref(r));331mpq_clear(r);332}333else if (!strcmp(argv[1], "--modular"))334{335if (argc <= 3)336{337cout << "not enough arguments" << endl;338return 0;339}340long p = atol(argv[2]);341long k = atol(argv[3]);342cout << bern_modp(p, k) << endl;343}344else345{346cout << "unknown command" << endl;347}348349return 0;350}351352353// end of file ================================================================354355356