Related
Consider that I need a n-sized vector where each element is defined between [-1,1]. The element a[i] is a float generated by -1 + 2*rand(). I need a elegant way to ensure that the sum of the elements of my array is equal to zero.
I've found two possible solutions:
The first one is this matlab function https://www.mathworks.com/matlabcentral/fileexchange/9700-random-vectors-with-fixed-sum. It has also a implementation in R, however it is too much work to implement it on C, since this function is used for a 2d array.
The second one is provided in this thread here: Generate random values with fixed sum in C++. Essentially, the idea is to generate n numbers with a normal distribution then normalize them to with my sum. (I have implemented it using python bellow) for a vector with sum up to 1.0. It works for every sum value except for zero.
import random as rd
mySum = 1;
randomVector = []
randomSum = 0
for i in range(7):
randomNumber = -1 + 2*rd.random()
randomVector.append(randomNumber)
randomSum += randomNumber
coef = mySum/randomSum
myNewList = [j * coef for j in randomVector]
newsum = sum(myNewList)
So, is there a way to do that using C or C++? If you know a already implemented function it would be awesome. Thanks.
I figured out a solution to your problem. This is not perfect since its randomness is limited by the range requirement.
The strategy is:
Define a function able to generate a random float in a customizable range. No need to reinvent the wheel: I borrowed it from https://stackoverflow.com/a/44105089/11336762
Malloc array (I omit pointer check in my example) and initialize the seed. In my example I just used current time but it can be improved
For every element to be generated, pre-calculate random range. Given the i-th sum, make sure that the next sum is NEVER out of range: if the sum is positive, the range needs to be (-1,1-sum); if it is negative it the range needs to be (-1-sum,1)
Do this until (n-1)th element. Last element must be directly assigned as the sum with the sign changed.
#include<stdio.h>
#include<stdlib.h>
#include<time.h>
float float_rand( float min, float max )
{
float scale = rand() / (float) RAND_MAX; /* [0, 1.0] */
return min + scale * ( max - min ); /* [min, max] */
}
void main( int argc, char *argv[] )
{
if( argc == 2 )
{
int i, n = atoi ( argv[1] );
float *outArr = malloc( n * sizeof( float ) );
float sum = 0;
printf( "Input value: %d\n\n", n );
/* Initialize seed */
srand ( time( NULL ) );
for( i=0; i<n-1; i++ )
{
/* Limit random generation range in order to make sure the next sum is *
* not outside (-1,1) range. */
float min = (sum<0? -1-sum : -1);
float max = (sum>0? 1-sum : 1);
outArr[i] = float_rand( min, max );
sum += outArr[i];
}
/* Set last array element */
outArr[n-1] = -sum;
/* Print results */
sum=0;
for( i=0; i<n; i++ )
{
sum += outArr[i];
printf( " outArr[%d]=%f \t(sum=%f)\n", i, outArr[i], sum );
}
free( outArr );
}
else
{
printf( "Only a parameter allowed (integer N)\n" );
}
}
I tried it, and it works also when n=1. In case of n=0 a sanity check should be added to my example.
Some output examples:
N=1:
Input value: 1
outArr[0]=-0.000000 (sum=-0.000000)
N=4
Input value: 4
outArr[0]=-0.804071 (sum=-0.804071)
outArr[1]=0.810685 (sum=0.006614)
outArr[2]=-0.353444 (sum=-0.346830)
outArr[3]=0.346830 (sum=0.000000)
N=8:
Input value: 8
outArr[0]=-0.791314 (sum=-0.791314)
outArr[1]=0.800182 (sum=0.008867)
outArr[2]=-0.571293 (sum=-0.562426)
outArr[3]=0.293300 (sum=-0.269126)
outArr[4]=-0.082886 (sum=-0.352012)
outArr[5]=0.818639 (sum=0.466628)
outArr[6]=-0.301473 (sum=0.165155)
outArr[7]=-0.165155 (sum=0.000000)
Thank you guys again for the help.
So, based on the idea of Cryostasys I developed the following C code to solve my problem:
#include <stdio.h> /* printf, scanf, puts, NULL */
#include <stdlib.h> /* srand, rand */
#include <time.h> /* time */
#include <math.h>
int main()
{
int arraySize = 10; //input value
double createdArray[arraySize]; //output value
double randomPositiveVector[arraySize];
double randomNegativeVector[arraySize];
double positiveSum = 0.;
double negativeSum = 0.;
srand(time(NULL)); //seed for random generation
for(int i = 0; i < arraySize; ++i)
{
double randomNumber = -1.+2.*rand()/((double) RAND_MAX); //random in [-1.0,1.0]
printf("%f\n",randomNumber);
if(randomNumber >=0)
{
randomPositiveVector[i] = randomNumber;
positiveSum += randomNumber;
}
else
{
randomNegativeVector[i] = randomNumber;
negativeSum += randomNumber;
}
}
if(positiveSum == 0. || negativeSum == 0.) printf("ERROR\n");
double positiveCoefficient = 1.0/positiveSum;
double negativeCoefficient = -1.0/negativeSum;
for(int i = 0; i < arraySize; ++i)
{
randomPositiveVector[i] = positiveCoefficient * randomPositiveVector[i];
randomNegativeVector[i] = negativeCoefficient * randomNegativeVector[i];
if(fabs(randomPositiveVector[i]) > 1e-6) //near to zero
{
createdArray[i] = randomPositiveVector[i];
}
else
{
createdArray[i] = randomNegativeVector[i];
}
}
for(int i = 0; i < arraySize; ++i)
{
printf("createdArray[%d] = %9f\n",i,createdArray[i]);
}
return(0);
}
Please note that the randomness of the values generated is decreased, as mentioned in the comments of the question. Also, the kind of random distribution is determined by the function that you use to generate the randomNumber above. In this case, I've used rand() from stdlib.h which is based on giving a seed to the function and it is going to generate a pseudo-random number. You could use a different option, for instance, drand48() from stdlib.h as well.
Nevertheless, it is required that at least one positive and one negative value is generated in order to this code work. One verification step was added to the code, and if it reaches this condition one should run again the code or do something about.
Output example (arraySize = 10):
createdArray[0] = -0.013824
createdArray[1] = 0.359639
createdArray[2] = -0.005851
createdArray[3] = 0.126829
createdArray[4] = -0.334745
createdArray[5] = -0.473096
createdArray[6] = -0.172484
createdArray[7] = 0.249523
createdArray[8] = 0.262370
createdArray[9] = 0.001640
One option is to generate some samples and then scale their values around the average. In C++ it would be something like the following
#include <iostream>
#include <iomanip>
#include <random>
#include <algorithm>
#include <cmath>
int main()
{
std::random_device rd;
std::seed_seq ss{rd(), rd(), rd(), rd()};
std::mt19937 gen{ss};
const int samples = 9;
// Generates the samples in [0, 2]
std::uniform_real_distribution dist(0.0, std::nextafter(2.0, 3.0));
std::vector<double> nums(samples);
double sum = 0.0;
for ( auto & i : nums )
{
i = dist(gen);
sum += i;
}
double average = sum / samples;
double k = 1.0 / std::max(average, 2.0 - average);
// Transform the values (apart from the last) to meet the requirements
sum = 0.0;
for ( size_t i = 0; i < nums.size() - 1; ++i )
{
nums[i] = (nums[i] - average) * k;
sum += nums[i];
};
// This trick (to ensure the needed precision) only works if the sum
// is always evaluated in the same order
nums.back() = 0.0 - sum;
sum = 0.0;
for ( size_t i = 0; i < nums.size(); ++i )
{
sum += nums[i];
std::cout << std::setw(10) << std::fixed << nums[i] << '\n';
}
if (sum != 0.0)
std::cout << "Failed.\n";
}
Testable here.
I want to generate (pseudo) random numbers between 0 and some integer. I don't mind if they aren't too random. I have access to the current time of the day but not the rand function. Can anyone think of a sufficiently robust way to generate these? Perhaps, discarding some bits from time of day and taking modulo my integer or something?
I am using c.
If you're after an ultra-simple pseudo-random generator, you can just use a Linear Feedback shift Register.
The wikipedia article has some code snippets for you to look at, but basically the code for a 16-bit generator will look something like this (lightly massaged from that page...)
unsigned short lfsr = 0xACE1u;
unsigned bit;
unsigned rand()
{
bit = ((lfsr >> 0) ^ (lfsr >> 2) ^ (lfsr >> 3) ^ (lfsr >> 5) ) & 1;
return lfsr = (lfsr >> 1) | (bit << 15);
}
For "not too random" integers, you could start with the current UNIX time, then use the recursive formula r = ((r * 7621) + 1) % 32768;. The nth random integer between 0 (inclusive) and M (exclusive) would be r % M after the nth iteration.
This is called a linear congruential generator.
The recursion formula is what bzip2 uses to select the pivot in its quicksort implementation. I wouldn't know about other purposes, but it works pretty well for this particular one...
Look at implementing a pseudo-random generator (what's "inside" rand()) of your own, for instance the Mersenne twister is highly-regarded.
#include <chrono>
int get_rand(int lo, int hi) {
auto moment = std::chrono::steady_clock::now().time_since_epoch().count();
int num = moment % (hi - lo + 1);
return num + lo;
}
The only "robust" (not easily predictable) way of doing this is writing your own pseudo-random number generator and seeding it with the current time. Obligatory wikipedia link: http://en.wikipedia.org/wiki/Pseudorandom_number_generator
You can get the "Tiny Mersenne Twister" here: http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/TINYMT/index.html
it is pure c and simple to use. E.g. just using time:
#include "tinymt32.h"
// And if you can't link:
#include "tinymt32.c"
#include <time.h>
#include <stdio.h>
int main(int argc, const char* argv[])
{
tinymt32_t state;
uint32_t seed = time(0);
tinymt32_init(&state, seed);
for (int i=0; i<10; i++)
printf("random number %d: %u\n", i, (unsigned int)tinymt32_generate_uint32(&state));
}
The smallest and simple random generator which work with ranges is provided below with fully working example.
unsigned int MyRand(unsigned int start_range,unsigned int end_range)
{
static unsigned int rand = 0xACE1U; /* Any nonzero start state will work. */
/*check for valid range.*/
if(start_range == end_range) {
return start_range;
}
/*get the random in end-range.*/
rand += 0x3AD;
rand %= end_range;
/*get the random in start-range.*/
while(rand < start_range){
rand = rand + end_range - start_range;
}
return rand;
}
int main(void)
{
int i;
for (i = 0; i < 0xFF; i++)
{
printf("%u\t",MyRand(10,20));
}
return 0;
}
If you're not generating your numbers too fast (*1) and your upper limit is low enough (*2) and your "time of day" includes nanoseconds, just use those nanoseconds.
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
int nanorand(void) {
struct timespec p[1];
clock_gettime(CLOCK_MONOTONIC, p);
return p->tv_nsec % 1000;
}
int main(void) {
int r, x;
for (;;) {
r = nanorand();
do {
printf("please type %d (< 50 quits): ", r);
fflush(stdout);
if (scanf("%d", &x) != 1) exit(EXIT_FAILURE);
} while (x != r);
if (r < 50) break;
}
puts("");
return 0;
}
And a sample run ...
please type 769 (< 50 quits): 769
please type 185 (< 50 quits): 185
please type 44 (< 50 quits): 44
(*1) if you're using them interactively, one at a time
(*2) if you want numbers up to about 1000
You can write your own rand() function. Like:
Method 1: Using the Concept of static variable:
example code:
int random_number_gen(int min_range, int max_range){
static int rand_number = 199198; // any random number
rand_number = ((rand_number * rand_number) / 10 ) % 9890;
return rand_number % (max_range+1-min_range) + min_range ;
}
Method 2. Using a random/unique value, for example, the current time in microseconds.
#include<time.h>
#include <chrono>
using namespace std;
uint64_t timeSinceEpochMicrosec() {
using namespace std::chrono;
return duration_cast<microseconds>(system_clock::now().time_since_epoch()).count();
}
int random_number_gen(int min_range, int max_range){
long long int current_time = timeSinceEpochMicrosec();
int current_time_in_sec = current_time % 10000000;
int rand_number = current_time_in_sec % (max_range+1-min_range) + min_range ;
return rand_number;
}
import java.io.*;
public class random{
public static class p{
}
static long reg=0;
static long lfsr()
{
if(reg==0)
{
reg=145896027340307l;
}
long bit=(reg>>0^reg>>2^reg>>3^reg>>5)&1;
reg=reg>>1|bit<<62;
return reg;
}
static long getRand()
{
String s=String.valueOf(new p());
//System.out.println(s);
long n=0;
lfsr();
for(int i=0;i<s.length();i++)
{
n=n<<8|+s.charAt(i);
}
System.out.print(n+" "+System.currentTimeMillis()+" "+reg+" ");
n=n^System.currentTimeMillis()^reg;
return n;
}
public static void main(String args[])throws IOException
{
for(int i=0;i<400;i++)
{
System.out.println(getRand());
}
}
}
This is a random number generator where it is guaranteed that the sequence never repeats itself. I have paired time with object value (randomly put by java) with LFSR.
Advantages:
The sequence doesn't repeat itself
The sequence is new on every run
Disadvantages:
Only compatible with java. In C++, new object that is created is same on every run.
But there too time and LFSR parameters would put in enough randomness
It is slower than most PRNGs as an object needs to be created everytime a number is needed
#include<time.h>
int main(){
int num;
time_t sec;
sec=time(NULL);
printf("Enter the Range under which you want Random number:\n");
scanf("%d",&num);
if(num>0)
{
for(;;)
{
sec=sec%3600;
if(num>=sec)
{
printf("%ld\n",sec);
break;
}
sec=sec%num;
}
}
else
{
printf("Please Enter Positive Value!\n");
}
return 0;
}
#include<stdio.h>
#include<conio.h>
#include<stdlib.h>
int main()
{
unsigned int x,r,i;
// no of random no you want to generate
scanf("%d",&x);
// put the range of random no
scanf("%d",&r);
unsigned int *a=(unsigned int*)malloc(sizeof(unsigned int)*x);
for(i=0;i<x;i++)
printf("%d ",(a[i]%r)+1);
free(a);
getch();
return 0;
}
One of the simplest random number generator which not return allways the same value:
uint16_t simpleRand(void)
{
static uint16_t r = 5531; //dont realy care about start value
r+=941; //this value must be relative prime to 2^16, so we use all values
return r;
}
You can maybe get the time to set the start value if you dont want that the sequence starts always with the same value.
I have the following code which calculates, for the number of terms of your choosing, the square root of 6 * [ 1 + 1/(2^2) + 1/(3^2)....1/(n^2)]. In this case, I'm going with 100 terms. If I am given what the output should be, is there a way to, using my existing code, determine how many terms were used to get to that output?
#include <stdio.h>
#include <math.h>
int main(int argc, const char * argv[]) {
long double square = 0;
for (int i = 1; i <= 100; i++) {
long double squareExp = i*i;
square += 1/(squareExp);
}
long double sixTimes = 6 * square;
long double squareRoot = sqrt(sixTimes);
printf("%.8Lf", squareRoot);
return 0;
}
I tried making it so that I take the desired output (3.141592), squaring it and dividing by 6 to negative the square root and (*6), and tried running this code:
double temp = 3.141592 * 3.141592;
double tempB = temp / 6;
printf("%f\n", tempB);
int reachedZero = 0;
int valueOfN = 0;
long double square = 0;
while (square > 0) {
int i = 1;
square -= 1/i;
i++;
if (square <= 1) {
reachedZero = 1;
valueOfN = i;
break;
}
}
printf("%i", valueOfN);
return 0;
}
I can't figure out what to do. I want to take the number (after getting rid of the square root and multiplying by 6), and subtract numbers starting with 1, then 1/4, then 1/9, then 1/16...1/(n^2) until the number becomes negative. Once that happens, I set a flag and I know how many terms I needed to reach that #. I then set that specific counter to a variable, which I can print out.
#EugeneSh. This was a working solution for me. Basically matched the pi output I was looking for with my loop, checking it each time. Could have changed the for loop to a while loop but it works fine this way.
int main(int argc, const char * argv[]) {
long double square;
for (long i = 1; i>=1; i++) {
square += 1.0/(i*i);
long double sixTimes = sqrt(6 * square);
if (sixTimes >= 3.141592) {
printf("%li", i);
break;
}
}
return 0;
}
I was finding out the algorithm for finding out the square root without using sqrt function and then tried to put into programming. I end up with this working code in C++
#include <iostream>
using namespace std;
double SqrtNumber(double num)
{
double lower_bound=0;
double upper_bound=num;
double temp=0; /* ek edited this line */
int nCount = 50;
while(nCount != 0)
{
temp=(lower_bound+upper_bound)/2;
if(temp*temp==num)
{
return temp;
}
else if(temp*temp > num)
{
upper_bound = temp;
}
else
{
lower_bound = temp;
}
nCount--;
}
return temp;
}
int main()
{
double num;
cout<<"Enter the number\n";
cin>>num;
if(num < 0)
{
cout<<"Error: Negative number!";
return 0;
}
cout<<"Square roots are: +"<<sqrtnum(num) and <<" and -"<<sqrtnum(num);
return 0;
}
Now the problem is initializing the number of iterations nCount in the declaratione ( here it is 50). For example to find out square root of 36 it takes 22 iterations, so no problem whereas finding the square root of 15625 takes more than 50 iterations, So it would return the value of temp after 50 iterations. Please give a solution for this.
There is a better algorithm, which needs at most 6 iterations to converge to maximum precision for double numbers:
#include <math.h>
double sqrt(double x) {
if (x <= 0)
return 0; // if negative number throw an exception?
int exp = 0;
x = frexp(x, &exp); // extract binary exponent from x
if (exp & 1) { // we want exponent to be even
exp--;
x *= 2;
}
double y = (1+x)/2; // first approximation
double z = 0;
while (y != z) { // yes, we CAN compare doubles here!
z = y;
y = (y + x/y) / 2;
}
return ldexp(y, exp/2); // multiply answer by 2^(exp/2)
}
Algorithm starts with 1 as first approximation for square root value.
Then, on each step, it improves next approximation by taking average between current value y and x/y. If y = sqrt(x), it will be the same. If y > sqrt(x), then x/y < sqrt(x) by about the same amount. In other words, it will converge very fast.
UPDATE: To speed up convergence on very large or very small numbers, changed sqrt() function to extract binary exponent and compute square root from number in [1, 4) range. It now needs frexp() from <math.h> to get binary exponent, but it is possible to get this exponent by extracting bits from IEEE-754 number format without using frexp().
Why not try to use the Babylonian method for finding a square root.
Here is my code for it:
double sqrt(double number)
{
double error = 0.00001; //define the precision of your result
double s = number;
while ((s - number / s) > error) //loop until precision satisfied
{
s = (s + number / s) / 2;
}
return s;
}
Good luck!
Remove your nCount altogether (as there are some roots that this algorithm will take many iterations for).
double SqrtNumber(double num)
{
double lower_bound=0;
double upper_bound=num;
double temp=0;
while(fabs(num - (temp * temp)) > SOME_SMALL_VALUE)
{
temp = (lower_bound+upper_bound)/2;
if (temp*temp >= num)
{
upper_bound = temp;
}
else
{
lower_bound = temp;
}
}
return temp;
}
As I found this question is old and have many answers but I have an answer which is simple and working great..
#define EPSILON 0.0000001 // least minimum value for comparison
double SquareRoot(double _val) {
double low = 0;
double high = _val;
double mid = 0;
while (high - low > EPSILON) {
mid = low + (high - low) / 2; // finding mid value
if (mid*mid > _val) {
high = mid;
} else {
low = mid;
}
}
return mid;
}
I hope it will be helpful for future users.
if you need to find square root without using sqrt(),use root=pow(x,0.5).
Where x is value whose square root you need to find.
//long division method.
#include<iostream>
using namespace std;
int main() {
int n, i = 1, divisor, dividend, j = 1, digit;
cin >> n;
while (i * i < n) {
i = i + 1;
}
i = i - 1;
cout << i << '.';
divisor = 2 * i;
dividend = n - (i * i );
while( j <= 5) {
dividend = dividend * 100;
digit = 0;
while ((divisor * 10 + digit) * digit < dividend) {
digit = digit + 1;
}
digit = digit - 1;
cout << digit;
dividend = dividend - ((divisor * 10 + digit) * digit);
divisor = divisor * 10 + 2*digit;
j = j + 1;
}
cout << endl;
return 0;
}
Here is a very simple but unsafe approach to find the square-root of a number.
Unsafe because it only works by natural numbers, where you know that the base respectively the exponent are natural numbers. I had to use it for a task where i was neither allowed to use the #include<cmath> -library, nor i was allowed to use pointers.
potency = base ^ exponent
// FUNCTION: square-root
int sqrt(int x)
{
int quotient = 0;
int i = 0;
bool resultfound = false;
while (resultfound == false) {
if (i*i == x) {
quotient = i;
resultfound = true;
}
i++;
}
return quotient;
}
This a very simple recursive approach.
double mySqrt(double v, double test) {
if (abs(test * test - v) < 0.0001) {
return test;
}
double highOrLow = v / test;
return mySqrt(v, (test + highOrLow) / 2.0);
}
double mySqrt(double v) {
return mySqrt(v, v/2.0);
}
Here is a very awesome code to find sqrt and even faster than original sqrt function.
float InvSqrt (float x)
{
float xhalf = 0.5f*x;
int i = *(int*)&x;
i = 0x5f375a86 - (i>>1);
x = *(float*)&i;
x = x*(1.5f - xhalf*x*x);
x = x*(1.5f - xhalf*x*x);
x = x*(1.5f - xhalf*x*x);
x=1/x;
return x;
}
After looking at the previous responses, I hope this will help resolve any ambiguities. In case the similarities in the previous solutions and my solution are illusive, or this method of solving for roots is unclear, I've also made a graph which can be found here.
This is a working root function capable of solving for any nth-root
(default is square root for the sake of this question)
#include <cmath>
// for "pow" function
double sqrt(double A, double root = 2) {
const double e = 2.71828182846;
return pow(e,(pow(10.0,9.0)/root)*(1.0-(pow(A,-pow(10.0,-9.0)))));
}
Explanation:
click here for graph
This works via Taylor series, logarithmic properties, and a bit of algebra.
Take, for example:
log A = N
x
*Note: for square-root, N = 2; for any other root you only need to change the one variable, N.
1) Change the base, convert the base 'x' log function to natural log,
log A => ln(A)/ln(x) = N
x
2) Rearrange to isolate ln(x), and eventually just 'x',
ln(A)/N = ln(x)
3) Set both sides as exponents of 'e',
e^(ln(A)/N) = e^(ln(x)) >~{ e^ln(x) == x }~> e^(ln(A)/N) = x
4) Taylor series represents "ln" as an infinite series,
ln(x) = (k=1)Sigma: (1/k)(-1^(k+1))(k-1)^n
<~~~ expanded ~~~>
[(x-1)] - [(1/2)(x-1)^2] + [(1/3)(x-1)^3] - [(1/4)(x-1)^4] + . . .
*Note: Continue the series for increased accuracy. For brevity, 10^9 is used in my function which expresses the series convergence for the natural log with about 7 digits, or the 10-millionths place, for precision,
ln(x) = 10^9(1-x^(-10^(-9)))
5) Now, just plug in this equation for natural log into the simplified equation obtained in step 3.
e^[((10^9)/N)(1-A^(-10^-9)] = nth-root of (A)
6) This implementation might seem like overkill; however, its purpose is to demonstrate how you can solve for roots without having to guess and check. Also, it would enable you to replace the pow function from the cmath library with your own pow function:
double power(double base, double exponent) {
if (exponent == 0) return 1;
int wholeInt = (int)exponent;
double decimal = exponent - (double)wholeInt;
if (decimal) {
int powerInv = 1/decimal;
if (!wholeInt) return root(base,powerInv);
else return power(root(base,powerInv),wholeInt,true);
}
return power(base, exponent, true);
}
double power(double base, int exponent, bool flag) {
if (exponent < 0) return 1/power(base,-exponent,true);
if (exponent > 0) return base * power(base,exponent-1,true);
else return 1;
}
int root(int A, int root) {
return power(E,(1000000000000/root)*(1-(power(A,-0.000000000001))));
}
I have to print series :-
n*(n-1),n*(n-1)*(n-2),n*(n-1)*(n-2)*(n-3),n*(n-1)*(n-2)*(n-3)*(n-4)...,n!.
Problem is large value of n , it can go upto 37 and n! will obviously go out of bounds ?
I just cant get started , please help , how would you have tackled situation if you were in my place ?
It depends on the language you are using. Some languages automatically switch to a large integer package when numbers get too large for the machine's native integer representation. In other languages, just use a large integer library, which should handle 37! easily.
Wikipedia has a list of arbitrary-precision arithmetic libraries for some languages. There are also lots of other resources on the web.
3 year old problem looked fun.
Simple create a routine to "multiply" a string by a factor. Not highly efficient, yet gets the job done.
#include <stdlib.h>
#include <string.h>
void mult_array(char *x, unsigned factor) {
unsigned accumulator = 0;
size_t n = strlen(x);
size_t i = n;
while (i > 0) {
i--;
accumulator += (unsigned)(x[i]-'0')*factor;
x[i] = (char) (accumulator%10 + '0');
accumulator /= 10;
}
while (accumulator > 0) {
memmove(x+1, x, ++n);
x[i] = (char) (accumulator%10 + '0');
accumulator /= 10;
}
}
#include <stdio.h>
void AS_Factorial(unsigned n) {
char buf[1000]; // Right-size buffer (problem for another day)
sprintf(buf, "%u", n);
fputs(buf, stdout);
while (n>1) {
n--;
mult_array(buf, n);
printf(",%s", buf);
}
puts("");
}
Sample usage and output
int main(void) {
AS_Factorial(5);
AS_Factorial(37);
return 0;
}
5,20,60,120,120
37,1332,46620,1585080,52307640,1673844480,...,13763753091226345046315979581580902400000000
I have just tried BigInteger in Java and it works.
Working code for demonstration purpose:
import java.math.BigInteger;
public class Factorial {
public static int[] primes = {2,3,5,7,11,13,17,19,23,29,31,37};
public static BigInteger computeFactorial(int n) {
if (n==0) {
return new BigInteger(String.valueOf(1));
} else {
return new BigInteger(String.valueOf(n)).multiply(computeFactorial(n-1));
}
}
public static String getPowers(int n){
BigInteger input = computeFactorial(n);
StringBuilder sb = new StringBuilder();
int count = 0;
for (int i = 0; i < primes.length && input.intValue() != 1;) {
BigInteger[] result = input.divideAndRemainder(new BigInteger(String.valueOf(primes[i])));
if (result[1].intValue() == 0) {
input = input.divide(new BigInteger(String.valueOf(primes[i])));
count++;
if (input.intValue() == 1) {sb.append(primes[i] + "(" + count + ") ");}
} else {
if (count!=0)
sb.append(primes[i] + "(" + count + ") ");
count = 0;
i++;
}
}
return sb.toString();
}
public static void main(String[] args) {
System.out.println(getPowers(37));
}
}
Feel free to use it without worrying about copyright if you want.
Update: I didn't realize you were using C++ until now. In that case, you can give boost BigInteger a try.
You may use big integer, but however this still has some limitations, but even though, this datatype can handle a very large value. The value that the big integer can hold, ranges from
-9223372036854775808 to 9223372036854775807 for the signed big integer, and
0 to 18446744073709551615 for the unsigned big integer.
If you really plan to do some bigger value computation which is bigger than the big integer data type, why not try the GMP library?
As from what the site says, "GMP is a free library for arbitrary precision arithmetic, operating on signed integers, rational numbers, and floating point numbers. There is no practical limit to the precision except the ones implied by the available memory in the machine GMP runs on. GMP has a rich set of functions, and the functions have a regular interface." - gmplib.org
You could implement your own big-integer type if it's not permitted to use any thirdparty libraries. You can do something like that:
#include <iostream>
#include <iomanip>
#include <vector>
using namespace std;
const int base = 1000 * 1000 * 1000; // base value, should be the power of 10
const int lbase = 9; // lg(base)
void output_biginteger(vector<int>& a) {
cout << a.back();
for (int i = (int)a.size() - 2; i >= 0; --i)
cout << setw(lbase) << setfill('0') << a[i];
cout << endl;
}
void multiply_biginteger_by_integer(vector<int>& a, int b) {
int carry = 0;
for (int i = 0; i < (int)a.size(); ++i) {
long long cur = (long long)a[i] * b + carry;
carry = cur / base;
a[i] = cur % base;
}
if (carry > 0) {
a.push_back(carry);
}
}
int main() {
int n = 37; // input your n here
vector<int> current(1, n);
for (int i = n - 1; n >= 1; --n) {
multiply_biginteger_by_integer(current, i);
output_biginteger(current);
}
return 0;
}