Is there a C++ algorithm to calculate the least common multiple for multiple numbers, like lcm(3,6,12) or lcm(5,7,9,12)?
You can use std::accumulate and some helper functions:
#include <iostream>
#include <numeric>
int gcd(int a, int b)
{
for (;;)
{
if (a == 0) return b;
b %= a;
if (b == 0) return a;
a %= b;
}
}
int lcm(int a, int b)
{
int temp = gcd(a, b);
return temp ? (a / temp * b) : 0;
}
int main()
{
int arr[] = { 5, 7, 9, 12 };
int result = std::accumulate(arr, arr + 4, 1, lcm);
std::cout << result << '\n';
}
boost provides functions for calculation lcm of 2 numbers (see here)
Then using the fact that
lcm(a,b,c) = lcm(lcm(a,b),c)
You can easily calculate lcm for multiple numbers as well
As of C++17, you can use std::lcm.
And here is a little program that shows how to specialize it for multiple parameters
#include <numeric>
#include <iostream>
namespace math {
template <typename M, typename N>
constexpr auto lcm(const M& m, const N& n) {
return std::lcm(m, n);
}
template <typename M, typename ...Rest>
constexpr auto lcm(const M& first, const Rest&... rest) {
return std::lcm(first, lcm(rest...));
}
}
auto main() -> int {
std::cout << math::lcm(3, 6, 12, 36) << std::endl;
return 0;
}
See it in action here: https://wandbox.org/permlink/25jVinGytpvPaS4v
The algorithm isn't specific to C++. AFAIK, there's no standard library function.
To calculate the LCM, you first calculate the GCD (Greatest Common Divisor) using Euclids algorithm.
http://en.wikipedia.org/wiki/Greatest_common_divisor
The GCD algorithm is normally given for two parameters, but...
GCD (a, b, c) = GCD (a, GCD (b, c))
= GCD (b, GCD (a, c))
= GCD (c, GCD (a, b))
= ...
To calculate the LCM, use...
a * b
LCM (a, b) = ----------
GCD (a, b)
The logic for that is based on prime factorization. The more general form (more than two variables) is...
a b
LCM (a, b, ...) = GCD (a, b, ...) * --------------- * --------------- * ...
GCD (a, b, ...) GCD (a, b, ...)
EDIT - actually, I think that last bit may be wrong. The first LCM (for two parameters) is right, though.
Using GCC with C++14 following code worked for me:
#include <algorithm>
#include <vector>
std::vector<int> v{4, 6, 10};
auto lcm = std::accumulate(v.begin(), v.end(), 1, [](auto & a, auto & b) {
return abs(a * b) / std::__gcd(a, b);
});
In C++17 there is std::lcm function (http://en.cppreference.com/w/cpp/numeric/lcm) that could be used in accumulate directly.
Not built in to the standard library. You need to either build it yourself or get a library that did it. I bet Boost has one...
I just created gcd for multiple numbers:
#include <iostream>
using namespace std;
int dbd(int n, int k, int y = 0);
int main()
{
int h = 0, n, s;
cin >> n;
s = dbd(n, h);
cout << s;
}
int dbd(int n, int k, int y){
int d, x, h;
cin >> x;
while(x != y){
if(y == 0){
break;
}
if( x > y){
x = x - y;
}else{
y = y - x;
}
}
d = x;
k++;
if(k != n){
d = dbd(n, k, x);
}
return d;
}
dbd - gcd.
n - number of numbers.
/*
Copyright (c) 2011, Louis-Philippe Lessard
All rights reserved.
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
unsigned gcd ( unsigned a, unsigned b );
unsigned gcd_arr(unsigned * n, unsigned size);
unsigned lcm(unsigned a, unsigned b);
unsigned lcm_arr(unsigned * n, unsigned size);
int main()
{
unsigned test1[] = {8, 9, 12, 13, 39, 7, 16, 24, 26, 15};
unsigned test2[] = {2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048};
unsigned result;
result = gcd_arr(test1, sizeof(test1) / sizeof(test1[0]));
result = gcd_arr(test2, sizeof(test2) / sizeof(test2[0]));
result = lcm_arr(test1, sizeof(test1) / sizeof(test1[0]));
result = lcm_arr(test2, sizeof(test2) / sizeof(test2[0]));
return result;
}
/**
* Find the greatest common divisor of 2 numbers
* See http://en.wikipedia.org/wiki/Greatest_common_divisor
*
* #param[in] a First number
* #param[in] b Second number
* #return greatest common divisor
*/
unsigned gcd ( unsigned a, unsigned b )
{
unsigned c;
while ( a != 0 )
{
c = a;
a = b%a;
b = c;
}
return b;
}
/**
* Find the least common multiple of 2 numbers
* See http://en.wikipedia.org/wiki/Least_common_multiple
*
* #param[in] a First number
* #param[in] b Second number
* #return least common multiple
*/
unsigned lcm(unsigned a, unsigned b)
{
return (b / gcd(a, b) ) * a;
}
/**
* Find the greatest common divisor of an array of numbers
* See http://en.wikipedia.org/wiki/Greatest_common_divisor
*
* #param[in] n Pointer to an array of number
* #param[in] size Size of the array
* #return greatest common divisor
*/
unsigned gcd_arr(unsigned * n, unsigned size)
{
unsigned last_gcd, i;
if(size < 2) return 0;
last_gcd = gcd(n[0], n[1]);
for(i=2; i < size; i++)
{
last_gcd = gcd(last_gcd, n[i]);
}
return last_gcd;
}
/**
* Find the least common multiple of an array of numbers
* See http://en.wikipedia.org/wiki/Least_common_multiple
*
* #param[in] n Pointer to an array of number
* #param[in] size Size of the array
* #return least common multiple
*/
unsigned lcm_arr(unsigned * n, unsigned size)
{
unsigned last_lcm, i;
if(size < 2) return 0;
last_lcm = lcm(n[0], n[1]);
for(i=2; i < size; i++)
{
last_lcm = lcm(last_lcm, n[i]);
}
return last_lcm;
}
Source code reference
You can calculate LCM and or GCM in boost like this:
#include <boost/math/common_factor.hpp>
#include <algorithm>
#include <iterator>
int main()
{
using std::cout;
using std::endl;
cout << "The GCD and LCM of 6 and 15 are "
<< boost::math::gcd(6, 15) << " and "
<< boost::math::lcm(6, 15) << ", respectively."
<< endl;
cout << "The GCD and LCM of 8 and 9 are "
<< boost::math::static_gcd<8, 9>::value
<< " and "
<< boost::math::static_lcm<8, 9>::value
<< ", respectively." << endl;
}
(Example taken from http://www.boost.org/doc/libs/1_31_0/libs/math/doc/common_factor.html)
The Codes given above only discusses about evaluating LCM for multiple numbers however it is very likely to happen that while performing multiplications we may overflow integer limit for data type storage
*A Corner Case :- *
e.g.
if while evaluating you reach situation such that if LCM_till_now=1000000000000000 next_number_in_list=99999999999999 and Hence GCD=1 (as both of them are relatively co-prime to each other)
So if u perform operation (LCM_till_now*next_number_in_list) will not even fit in "unsigned long long int"
Remedy :-
1.Use Big Integer Class
2.Or if the problem is asking for LCM%MOD----------->then apply properties of modular arithmetic.
Using the fact that lcm should be divisible
by all the numbers in list. Here the list is a vector containing numbers
int lcm=*(len.begin());
int ini=lcm;
int val;
int i=1;
for(it=len.begin()+1;it!=len.end();it++)
{
val=*it;
while(lcm%(val)!=0)
{
lcm+=ini;
}
ini=lcm;
}
printf("%llu\n",lcm);
len.clear();
I found this while searching a similar problem and wanted to contribute what I came up with for two numbers.
#include <iostream>
#include <algorithm>
using namespace std;
int main()
{
cin >> x >> y;
// zero is not a common multiple so error out
if (x * y == 0)
return -1;
int n = min(x, y);
while (max(x, y) % n)
n--;
cout << n << endl;
}
#include<iostream>
using namespace std;
int lcm(int, int, int);
int main()
{
int a, b, c, ans;
cout<<"Enter the numbers to find its LCM"<<endl; //NOTE: LCM can be found only for non zero numbers.
cout<<"A = "; cin>>a;
cout<<"B = "; cin>>b;
cout<<"C = "; cin>>c;
ans = lcm(a,b,c);
cout<<"LCM of A B and C is "<<ans;
}
int lcm(int a, int b, int c){
static int i=1;
if(i%a == 0 && i%b == 0 && i%c ==0){ //this can be altered according to the number of parameters required i.e this is for three inputs
return i;
} else {
i++;
lcm(a,b,c);
return i;
}
}
If you look at this page, you can see a fairly simple algorithm you could use. :-)
I'm not saying it's efficient or anything, mind, but it does conceptually scale to multiple numbers. You only need space for keeping track of your original numbers and a cloned set that you manipulate until you find the LCM.
#include
#include
void main()
{
clrscr();
int x,y,gcd=1;
cout<>x;
cout<>y;
for(int i=1;i<1000;++i)
{
if((x%i==0)&&(y%i==0))
gcd=i;
}
cout<<"\n\n\nGCD :"<
cout<<"\n\n\nLCM :"<<(x*y)/gcd;
getch();
}
let the set of numbers whose lcm you wish to calculate be theta
let i, the multiplier, be = 1
let x = the largest number in theta
x * i
if for every element j in theta, (x*i)%j=0 then x*i is the least LCM
if not, loop, and increment i by 1
Related
Hope you can help me; I have the following code:
#include <iostream>
#include <math.h>
using namespace std;
long int
cifra (long int b, long int e, long int n)
{
/* Calcula a tal que (b^e)=a MOD n. Algoritmo 3.1 de Allenby & Redfern,1989. */
long int a, i, q, r;
a = 1;
q = b / n;
r = b - q * n;
for (i = 1; i <= e; i++)
{
a = a * r;
q = a / n;
a = a - q * n; /* ou, de forma equivalente, a=mod(a,n) */
}
return a;
}
int
main ()
{
long int a, b, e, n;
b = 116104101;
e = 19661;
n = 383768051;
a = cifra (b, e, n);
cout << "a=" << a << endl;
return 0;
}
and this should output
a=199324862
as it does when I used the online C++ Compiler (https://www.onlinegdb.com/online_c++_compiler, which uses g++).
However: if I run it on Code::Blocks with MinGW64 (on Windows 10), I get the wrong result:
a=298405922
Any ideas? Am I doing anything wrong?
Overflow
q * n, a * r, q * n risk overflow.
The width of long is at least 32-bit, yet a full range multiplication obliges 2x long width for the product. On some platforms it is 64-bit and thus success with the test values on some, failure on others.
Either:
Use a wider type for intermediate calculations. long long would suffice for OP's test case of b = 116104101; e = 19661; n = 383768051; yet still fail with long long for b = 116104101<<32; e = 19661<<32; n = 383768051<<32;
or
Perform the math more carefully. Example: Modular exponentiation without range restriction.
Slow
for (i = 1; i <= e; i++) is very slow with large e. Research Modular exponentiation.
Bug
int64_t cifra(int64_t b, int64_t e, int64_t n) incorrect with some small corner cases. cifra(b, 0, 1) returns 1 when it should return 0.
// a = 1;
a = n > 1 ? 1 : 0;
// or
a = 1%n;
// or ...
Sample fix
Example fix for OP's code with limited range. I went for unsigned types as analyzing signed types with negative values is too tedious right now.
uint32_t cifra32(uint32_t b, uint32_t e, uint32_t n) {
uint64_t a = 1%n;
uint64_t q = b / n;
uint64_t r = b - q * n;
for (uint32_t i = 1; i <= e; i++) {
a = a * r;
q = a / n;
a = a - q * n;
}
return a;
}
More improvements possible.
It seems that you're assuming that long int is a 64-bit (or larger) integer type, but it's actually a 32-bit type in that particular environment. If you need a certain size type you should use something more explicit like int64_t or uint64_t. Also, you might want to use the remainder operator % to avoid the q variable altogether, e.g. r = b % n or just b %= n:
#include <iostream>
#include <cstdint>
int64_t cifra(int64_t b, int64_t e, int64_t n) {
/* Calcula a tal que (b^e)=a MOD n. Algoritmo 3.1 de Allenby & Redfern,1989. */
int64_t a, i;
a = 1;
b %= n;
for (i = 1; i <= e; i++) {
a = (a * b) % n; /* ou, de forma equivalente, a=mod(a,n) */
}
return a;
}
int main() {
int64_t a, b, e, n;
b = 116104101;
e = 19661;
n = 383768051;
a = cifra(b, e, n);
std::cout << "a=" << a << std::endl;
return 0;
}
So I've decided to take a stab at implementing Karatsuba's algorithm in C++ (haven't used this language since my second coding class a life time ago so I'm very very rusty). Well anyhow, I believe that I've followed the pseudocode line by line but my algorithm still keeps popping up with the wrong answer.
x = 1234, y = 5678
Actual Answer: x*y ==> 7006652
Program output: x*y ==> 12272852
*Note: I'm running on a mac and using the following to create the executable to run c++ -std=c++11 -stdlib=libc++ karatsuba.cpp
Anywho, here's the code drafted up and feel free to make some callouts on what I'm doing wrong or how to improve upon c++.
Thanks!
Code:
#include <iostream>
#include <tuple>
#include <cmath>
#include <math.h>
using namespace std;
/** Method signatures **/
tuple<int, int> splitHalves(int x);
int karatsuba(int x, int y, int n);
int main()
{
int x = 5678;
int y = 1234;
int xy = karatsuba(x, y, 4);
cout << xy << endl;
return 0;
}
int karatsuba(int x, int y, int n)
{
if (n == 1)
{
return x * y;
}
else
{
int a, b, c, d;
tie(a, b) = splitHalves(x);
tie(c, d) = splitHalves(y);
int p = a + b;
int q = b + c;
int ac = karatsuba(a, c, round(n / 2));
int bd = karatsuba(b, d, round(n / 2));
int pq = karatsuba(p, q, round(n / 2));
int acbd = pq - bd - ac;
return pow(10, n) * ac + pow(10, round(n / 2)) * acbd + bd;
}
}
/**
* Method taken from https://stackoverflow.com/questions/32016815/split-integer-into-two-separate-integers#answer-32017073
*/
tuple<int, int> splitHalves(int x)
{
const unsigned int Base = 10;
unsigned int divisor = Base;
while (x / divisor > divisor)
divisor *= Base;
return make_tuple(round(x / divisor), x % divisor);
}
There are a lot of problems in your code...
First, you have a wrong coefficient here:
int q = b + c;
Has to be:
int q = c + d;
Next, the implementation of splitHalves doesn't do the work. Try that:
tuple<int, int> splitHalves(int x, int power)
{
int divisor = pow(10, power);
return make_tuple(x / divisor, x % divisor);
}
That would give you the "correct" answer for your input, but... that is not a Karatsuba method.
First, keep in mind that you don't need to "split in halves". Consider 12 * 3456. splitting the first number to halves mean a = 0, b = 12, while your implementation gives a = 1, b = 2.
Overall Karastuba works with arrays, not integers.
I want a function
int rounded_division(const int a, const int b) {
return round(1.0 * a/b);
}
So we have, for example,
rounded_division(3, 2) // = 2
rounded_division(2, 2) // = 1
rounded_division(1, 2) // = 1
rounded_division(0, 2) // = 0
rounded_division(-1, 2) // = -1
rounded_division(-2, 2) // = -1
rounded_division(-3, -2) // = 2
Or in code, where a and b are 32 bit signed integers:
int rounded_division(const int a, const int b) {
return ((a < 0) ^ (b < 0)) ? ((a - b / 2) / b) : ((a + b / 2) / b);
}
And here comes the tricky part: How to implement this guy efficiently (not using larger 64 bit values) and without a logical operators such as ?:, &&, ...? Is it possible at all?
The reason why I am wondering of avoiding logical operators, because the processor I have to implement this function for, has no conditional instructions (more about missing conditional instructions on ARM.).
a/b + a%b/(b/2 + b%2) works quite well - not failed in billion+ test cases. It meets all OP's goals: No overflow, no long long, no branching, works over entire range of int when a/b is defined.
No 32-bit dependency. If using C99 or later, no implementation behavior restrictions.
int rounded_division(int a, int b) {
int q = a / b;
int r = a % b;
return q + r/(b/2 + b%2);
}
This works with 2's complement, 1s' complement and sign-magnitude as all operations are math ones.
How about this:
int rounded_division(const int a, const int b) {
return (a + b/2 + b * ((a^b) >> 31))/b;
}
(a ^ b) >> 31 should evaluate to -1 if a and b have different signs and 0 otherwise, assuming int has 32 bits and the leftmost is the sign bit.
EDIT
As pointed out by #chux in his comments this method is wrong due to integer division. This new version evaluates the same as OP's example, but contains a bit more operations.
int rounded_division(const int a, const int b) {
return (a + b * (1 + 2 * ((a^b) >> 31)) / 2)/b;
}
This version still however does not take into account the overflow problem.
What about
...
return ((a + (a*b)/abs(a*b) * b / 2) / b);
}
Without overflow:
...
return ((a + ((a/abs(a))*(b/abs(b))) * b / 2) / b);
}
This is a rough approach that you may use. Using a mask to apply something if the operation a*b < 0.
Please note that I did not test this appropriately.
int function(int a, int b){
int tmp = float(a)/b + 0.5;
int mask = (a*b) >> 31; // shift sign bit to set rest of the bits
return tmp - (1 & mask);//minus one if a*b was < 0
}
The following rounded_division_test1() meets OP's requirement of no branching - if one counts sign(int a), nabs(int a), and cmp_le(int a, int b) as non-branching. See here for ideas of how to do sign() without compare operators. These helper functions could be rolled into rounded_division_test1() without explicit calls.
The code demonstrates the correct functionality and is useful for testing various answers. When a/b is defined, this answer does not overflow.
#include <limits.h>
#include <math.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
int nabs(int a) {
return (a < 0) * a - (a >= 0) * a;
}
int sign(int a) {
return (a > 0) - (a < 0);
}
int cmp_le(int a, int b) {
return (a <= b);
}
int rounded_division_test1(int a, int b) {
int q = a / b;
int r = a % b;
int flag = cmp_le(nabs(r), (nabs(b) / 2 + nabs(b % 2)));
return q + flag * sign(b) * sign(r);
}
// Alternative that uses long long
int rounded_division_test1LL(int a, int b) {
int c = (a^b)>>31;
return (a + (c*2 + 1)*1LL*b/2)/b;
}
// Reference code
int rounded_division(int a, int b) {
return round(1.0*a/b);
}
int test(int a, int b) {
int q0 = rounded_division(a, b);
//int q1 = function(a,b);
int q1 = rounded_division_test1(a, b);
if (q0 != q1) {
printf("%d %d --> %d %d\n", a, b, q0, q1);
fflush(stdout);
}
return q0 != q1;
}
void tests(void) {
int err = 0;
int const a[] = { INT_MIN, INT_MIN + 1, INT_MIN + 1, -3, -2, -1, 0, 1, 2, 3,
INT_MAX - 1, INT_MAX };
for (unsigned i = 0; i < sizeof a / sizeof a[0]; i++) {
for (unsigned j = 0; j < sizeof a / sizeof a[0]; j++) {
if (a[j] == 0) continue;
if (a[i] == INT_MIN && a[j] == -1) continue;
err += test(a[i], a[j]);
}
}
printf("Err %d\n", err);
}
int main(void) {
tests();
return 0;
}
Let me give my contribution:
What about:
int rounded_division(const int a, const int b) {
return a/b + (2*(a%b))/b;
}
No branch, no logical operators, only mathematical operators. But it could fail if b is great than INT_MAX/2 or less than INT_MIN/2.
But if 64 bits are allowed to compute 32 bits rounds. It will not fail
int rounded_division(const int a, const int b) {
return a/b + (2LL*(a%b))/b;
}
Code that I came up with for use on ARM M0 (no floating point, slow divide).
It only uses one divide instruction and no conditionals, but will overflow if numerator + (denominator/2) > INT_MAX.
Cycle count on ARM M0 = 7 cycles + the divide (M0 has no divide instruction, so it is toolchain dependant).
int32_t Int32_SignOf(int32_t val)
{
return (+1 | (val >> 31)); // if v < 0 then -1, else +1
}
uint32_t Int32_Abs(int32_t val)
{
int32_t tmp = val ^ (val >> 31);
return (tmp - (val >> 31));
// the following code looks like it should be faster, using subexpression elimination
// except on arm a bitshift is free when performed with another operation,
// so it would actually end up being slower
// tmp = val >> 31;
// dst = val ^ (tmp);
// dst -= tmp;
// return dst;
}
int32_t Int32_DivRound(int32_t numerator, int32_t denominator)
{
// use the absolute (unsigned) demominator in the fudge value
// as the divide by 2 then becomes a bitshift
int32_t sign_num = Int32_SignOf(numerator);
uint32_t abs_denom = Int32_Abs(denominator);
return (numerator + sign_num * ((int32_t)(abs_denom / 2u))) / denominator;
}
since the function seems to be symmetric how about sign(a/b)*floor(abs(a/b)+0.5)
I want to find (n choose r) for large integers, and I also have to find out the mod of that number.
long long int choose(int a,int b)
{
if (b > a)
return (-1);
if(b==0 || a==1 || b==a)
return(1);
else
{
long long int r = ((choose(a-1,b))%10000007+(choose(a-1,b- 1))%10000007)%10000007;
return r;
}
}
I am using this piece of code, but I am getting TLE. If there is some other method to do that please tell me.
I don't have the reputation to comment yet, but I wanted to point out that the answer by rock321987 works pretty well:
It is fast and correct up to and including C(62, 31)
but cannot handle all inputs that have an output that fits in a uint64_t. As proof, try:
C(67, 33) = 14,226,520,737,620,288,370 (verify correctness and size)
Unfortunately, the other implementation spits out 8,829,174,638,479,413 which is incorrect. There are other ways to calculate nCr which won't break like this, however the real problem here is that there is no attempt to take advantage of the modulus.
Notice that p = 10000007 is prime, which allows us to leverage the fact that all integers have an inverse mod p, and that inverse is unique. Furthermore, we can find that inverse quite quickly. Another question has an answer on how to do that here, which I've replicated below.
This is handy since:
x/y mod p == x*(y inverse) mod p; and
xy mod p == (x mod p)(y mod p)
Modifying the other code a bit, and generalizing the problem we have the following:
#include <iostream>
#include <assert.h>
// p MUST be prime and less than 2^63
uint64_t inverseModp(uint64_t a, uint64_t p) {
assert(p < (1ull << 63));
assert(a < p);
assert(a != 0);
uint64_t ex = p-2, result = 1;
while (ex > 0) {
if (ex % 2 == 1) {
result = (result*a) % p;
}
a = (a*a) % p;
ex /= 2;
}
return result;
}
// p MUST be prime
uint32_t nCrModp(uint32_t n, uint32_t r, uint32_t p)
{
assert(r <= n);
if (r > n-r) r = n-r;
if (r == 0) return 1;
if(n/p - (n-r)/p > r/p) return 0;
uint64_t result = 1; //intermediary results may overflow 32 bits
for (uint32_t i = n, x = 1; i > r; --i, ++x) {
if( i % p != 0) {
result *= i % p;
result %= p;
}
if( x % p != 0) {
result *= inverseModp(x % p, p);
result %= p;
}
}
return result;
}
int main() {
uint32_t smallPrime = 17;
uint32_t medNum = 3001;
uint32_t halfMedNum = medNum >> 1;
std::cout << nCrModp(medNum, halfMedNum, smallPrime) << std::endl;
uint32_t bigPrime = 4294967291ul; // 2^32-5 is largest prime < 2^32
uint32_t bigNum = 1ul << 24;
uint32_t halfBigNum = bigNum >> 1;
std::cout << nCrModp(bigNum, halfBigNum, bigPrime) << std::endl;
}
Which should produce results for any set of 32-bit inputs if you are willing to wait. To prove a point, I've included the calculation for a 24-bit n, and the maximum 32-bit prime. My modest PC took ~13 seconds to calculate this. Check the answer against wolfram alpha, but beware that it may exceed the 'standard computation time' there.
There is still room for improvement if p is much smaller than (n-r) where r <= n-r. For example, we could precalculate all the inverses mod p instead of doing it on demand several times over.
nCr = n! / (r! * (n-r)!) {! = factorial}
now choose r or n - r in such a way that any of them is minimum
#include <cstdio>
#include <cmath>
#define MOD 10000007
int main()
{
int n, r, i, x = 1;
long long int res = 1;
scanf("%d%d", &n, &r);
int mini = fmin(r, (n - r));//minimum of r,n-r
for (i = n;i > mini;i--) {
res = (res * i) / x;
x++;
}
printf("%lld\n", res % MOD);
return 0;
}
it will work for most cases as required by programming competitions if the value of n and r are not too high
Time complexity :- O(min(r, n - r))
Limitation :- for languages like C/C++ etc. there will be overflow if
n > 60 (approximately)
as no datatype can store the final value..
The expansion of nCr can always be reduced to product of integers. This is done by canceling out terms in denominator. This approach is applied in the function given below.
This function has time complexity of O(n^2 * log(n)). This will calculate nCr % m for n<=10000 under 1 sec.
#include <numeric>
#include <algorithm>
int M=1e7+7;
int ncr(int n, int r)
{
r=min(r,n-r);
int A[r],i,j,B[r];
iota(A,A+r,n-r+1); //initializing A starting from n-r+1 to n
iota(B,B+r,1); //initializing B starting from 1 to r
int g;
for(i=0;i<r;i++)
for(j=0;j<r;j++)
{
if(B[i]==1)
break;
g=__gcd(B[i], A[j] );
A[j]/=g;
B[i]/=g;
}
long long ans=1;
for(i=0;i<r;i++)
ans=(ans*A[i])%M;
return ans;
}
My code works when the values are small e.g. [a = 1, gos = 0.5, N = 1] & [a = 1, gos = 0.2 , N = 2].
However, it crashes when bigger values are entered. e.g.[a = 10, gos = 0.01, N = 18] & [a=50, gos=0.01, N=64].
How can I fix it?
Here's the code:
#include <cstdlib>
#include <iostream>
using namespace std;
double num_trunks(double A, double B, int N);
double num_trunk_checker(double B, double gos, int N, double A);
double num_trunks(double A, double B, int N)
{
double gos_prev = 1;
double gos;
int k = 1;
while (k != (N+1))
{
gos = (A*gos_prev)/(k+(gos_prev)*A);
gos_prev = gos;
k++;
};
num_trunk_checker(B,gos,N,A);
}
double num_trunk_checker(double B, double gos, int N, double A)
{
if (B != gos)
{
N = N + 1;
num_trunks(A,B,N);
}
else
{
cout << "Number of trunks: " << N << "\n";
}
}
int main(int argc, char *argv[])
{
double A, gos;
int N = 1;
cout << "A: ";
cin >> A;
cout << "gos: ";
cin >> gos;
num_trunks(A,gos,N);
system("PAUSE");
return EXIT_SUCCESS;
}
In num_trunks(A, B, N), you calculate a gos value, and then call num_trunk_checker(B, gos, N, A). But in num_trunk_checker, if B does not match gos, you turn around and call num_trunks(A, B, N+1). So the only thing that changed is a larger N, and you get infinite recursion if gos never equals B.
num_trunks(A, B, N)
calculuate gos (which has to be less than 1)
num_trunk_checker(B, gos, N, A)
num_trunk_checker(B, gos, N, A)
if (B != gos) num_trunks(A, B, N+1)
It is possible for gos to step over the value of B, so you never get equality.
Perhaps what you meant was:
if (gos > B) //...
you should read the FAQ about floating point comparisons
http://www.parashift.com/c++-faq/floating-point-arith.html
then try sth like
if (fabs(B-gos)<1.e-6)
in num_trunk_checker function
Without more information (what crashes? How long does it take?) it is impossible to solve your problem perfectly. But some reasonable guesses can be made.
Floating point comparisons are not completely accurate and are usually done by subtracting the two values and comparing against a small value (called epsilon). It might be better, when checking (B != gos), to do something like (B - gos < .00001). Without this, the computation may not terminate; and if it did not, the recursion would continue indefinitely, until the stack overflowed and the program crashed.
Another possibility (I am not running the program to see what happens myself) is that with larger values, the multiplication causes them to overflow (to exceed the maximum possible value that can be represented in a double), causing an exception to be thrown.