I'm trying to write a program that calculates decimal digits of π to 1000 digits or more.
To practice low-level programming for fun, the final program will be written in assembly, on a 8-bit CPU that has no multiplication or division, and only performs 16-bit additions. To ease the implementation, it's desirable to be able to use only 16-bit unsigned integer operations, and use an iterative algorithm. Speed is not a major concern. And fast multiplication and division is beyond the scope of this question, so don't consider those issues as well.
Before implementing it in assembly, I'm still trying to figure out an usable algorithm in C on my desktop computer. So far, I found the following series is reasonably efficient and relatively easy to implement.
The formula is derived from the Leibniz Series using a convergence acceleration technique, To derive it, see Computing the Digits in π, by Carl D. Offner (https://cs.umb.edu/~offner/files/pi.pdf), page 19-26. The final formula is shown in page 26. The initial formula I've written had some typos, please refresh the page to see the fixed formula. The constant term 2 at the greatest term is explained in page 54. The paper described an advanced iterative algorithm as well, but I didn't use it here.
If one evaluates the series using many (e.g. 5000) terms, it's possible to get thousands digits of π easily, and I found this series is easy to evaluate iteratively as well using this algorithm:
Algorithm
First, rearrange the formula to obtain its constant terms from an array.
Fill the array with 2 to start the first iteration, hence the new formula resembles the original one.
Let carry = 0.
Start from the greatest term. Obtain one term (2) from the array, multiply the term by PRECISION to perform a fixed-point division against 2 * i + 1, and save the reminder as the new term to the array. Then add the next term. Now decrement i, go to the next term, repeat until i == 1. Finally add the final term x_0.
Because 16-bit integer is used, PRECISION is 10, hence 2 decimal digits are obtained, but only the first digit is valid. Save the second digit as carry. Show the first digit plus carry.
x_0 is the integer 2, it should not be added for the successive iterations, clear it.
Goto step 4 to calculate the next decimal digit, until we have all the digits we want.
Implementation 1
Translating this algorithm to C:
#include <stdio.h>
#include <stdint.h>
#define N 2160
#define PRECISION 10
uint16_t terms[N + 1] = {0};
int main(void)
{
/* initialize the initial terms */
for (size_t i = 0; i < N + 1; i++) {
terms[i] = 2;
}
uint16_t carry = 0;
for (size_t j = 0; j < N / 4; j++) {
uint16_t numerator = 0;
uint16_t denominator;
uint16_t digit;
for (size_t i = N; i > 0; i--) {
numerator += terms[i] * PRECISION;
denominator = 2 * i + 1;
terms[i] = numerator % denominator;
numerator /= denominator;
numerator *= i;
}
numerator += terms[0] * PRECISION;
digit = numerator / PRECISION + carry;
carry = numerator % PRECISION;
printf("%01u", digit);
/* constant term 2, only needed for the first iteration. */
terms[0] = 0;
}
putchar('\n');
}
The code can calculate π to 31 decimal digits, until it makes an error.
31415926535897932384626433832794
10 <-- wrong
Sometimes digit + carry is greater than 9, so it needs an extra carry. If we are very unlucky, there may even be a double carry, triple carry, etc. We use a ring-buffer to store the last 4 digits. If an extra carry is detected, we output a backspace to erase the previous digit, perform a carry, and reprint them. This is just a ugly solution to the Proof-of-Concept, which is irrelevant to my question about overflow, but for completeness, here is it. Something better would be implemented in the future.
Implementation 2 with Repeated Carry
#include <stdio.h>
#include <stdint.h>
#define N 2160
#define PRECISION 10
#define BUF_SIZE 4
uint16_t terms[N + 1] = {0};
int main(void)
{
/* initialize the initial terms */
for (size_t i = 0; i < N + 1; i++) {
terms[i] = 2;
}
uint16_t carry = 0;
uint16_t digit[BUF_SIZE];
int8_t idx = 0;
for (size_t j = 0; j < N / 4; j++) {
uint16_t numerator = 0;
uint16_t denominator;
for (size_t i = N; i > 0; i--) {
numerator += terms[i] * PRECISION;
denominator = 2 * i + 1;
terms[i] = numerator % denominator;
numerator /= denominator;
numerator *= i;
}
numerator += terms[0] * PRECISION;
digit[idx] = numerator / PRECISION + carry;
/* over 9, needs at least one carry op. */
if (digit[idx] > 9) {
for (int i = 1; i <= 4; i++) {
if (i > 3) {
/* allow up to 3 consecutive carry ops */
fprintf(stderr, "ERROR: too many carry ops!\n");
return 1;
}
/* erase a digit */
putchar('\b');
/* carry */
digit[idx] -= 10;
idx--;
if (idx < 0) {
idx = BUF_SIZE - 1;
}
digit[idx]++;
if (digit[idx] < 10) {
/* done! reprint the digits */
for (int j = 0; j <= i; j++) {
printf("%01u", digit[idx]);
idx++;
if (idx > BUF_SIZE - 1) {
idx = 0;
}
}
break;
}
}
}
else {
printf("%01u", digit[idx]);
}
carry = numerator % PRECISION;
terms[0] = 0;
/* put an element to the ring buffer */
idx++;
if (idx > BUF_SIZE - 1) {
idx = 0;
}
}
putchar('\n');
}
Great, now the program can correctly calculate 534 digits of π, until it makes an
error.
3141592653589793238462643383279502884
1971693993751058209749445923078164062
8620899862803482534211706798214808651
3282306647093844609550582231725359408
1284811174502841027019385211055596446
2294895493038196442881097566593344612
8475648233786783165271201909145648566
9234603486104543266482133936072602491
4127372458700660631558817488152092096
2829254091715364367892590360011330530
5488204665213841469519415116094330572
7036575959195309218611738193261179310
5118548074462379962749567351885752724
8912279381830119491298336733624406566
43086021394946395
22421 <-- wrong
16-bit Integer Overflow
It turns out, during the calculation of the largest terms at the beginning, the error term gets quite large, since the divisors at the beginning are in the range of ~4000. When evaluating the series, numerator actually starts to overflow in the multiplication immediately.
The integer overflow is insignificant when calculating the first 500 digits, but starts to get worse and worse, until it gives an incorrect result.
Changing uint16_t numerator = 0 to uint32_t numerator = 0 can solve this problem and calculate π to 1000+ digits.
However, as I mentioned before, my target platform is a 8-bit CPU, and only has 16-bit operations. Is there a trick to solve the 16-bit integer overflow issue that I'm seeing here, using only one or more uint16_t? If it's not possible to avoid multiple-precision arithmetic, what is the simplest method to implement it here? I know somehow I need to introduce an extra 16-bit "extension word", but I'm not sure how can I implement it.
And thanks in advance for your patience to understand the long context here.
Take a look at related QA:
Baking-Pi Challenge - Understanding & Improving
Its using Wiki: Bailey–Borwein–Plouffe_formula which is more suited for integer arithmetics.
The real challenge however would be:
How do I convert a very long binary number to decimal?.
As you probably want to print the number in dec base ...
Also if you need carry in higher level language than asm take a look at this:
Cant make value propagate through carry
You can modify it to handle as many carry bits as you need (if still less than the data type bit-width).
[Edit1] BBP example in C++/VCL
I used this formula (taken from Wiki page linked above):
converted to fixed point...
//---------------------------------------------------------------------------
AnsiString str_hex2dec(const AnsiString &hex)
{
char c;
AnsiString dec="",s;
int i,j,l,ll,cy,val;
int i0,i1,i2,i3,sig;
sig=+1; l=hex.Length();
if (l) { c=hex[l]; if (c=='h') l--; if (c=='H') l--; }
i0=0; i1=l; i2=0; i3=l;
for (i=1;i<=l;i++) // scan for parts of number
{
char c=hex[i];
if (c=='-') sig=-sig;
if ((c=='.')||(c==',')) i1=i-1;
if ((c>='0')&&(c<='9')) { if (!i0) i0=i; if ((!i2)&&(i>i1)) i2=i; }
if ((c>='A')&&(c<='F')) { if (!i0) i0=i; if ((!i2)&&(i>i1)) i2=i; }
if ((c>='a')&&(c<='f')) { if (!i0) i0=i; if ((!i2)&&(i>i1)) i2=i; }
}
l=0; s=""; if (i0) for (i=i0;i<=i1;i++)
{
c=hex[i];
if ((c>='0')&&(c<='9')) c-='0';
else if ((c>='A')&&(c<='F')) c-='A'-10;
else if ((c>='a')&&(c<='f')) c-='A'-10;
for (cy=c,j=1;j<=l;j++)
{
val=(s[j]<<4)+cy;
s[j]=val%10;
cy =val/10;
}
while (cy>0)
{
l++;
s+=char(cy%10);
cy/=10;
}
}
if (s!="")
{
for (j=1;j<=l;j++) { c=s[j]; if (c<10) c+='0'; else c+='A'-10; s[j]=c; }
for (i=l,j=1;j<i;j++,i--) { c=s[i]; s[i]=s[j]; s[j]=c; }
dec+=s;
}
if (dec=="") dec="0";
if (sig<0) dec="-"+dec;
if (i2)
{
dec+='.';
s=hex.SubString(i2,i3-i2+1);
l=s.Length();
for (i=1;i<=l;i++)
{
c=s[i];
if ((c>='0')&&(c<='9')) c-='0';
else if ((c>='A')&&(c<='F')) c-='A'-10;
else if ((c>='a')&&(c<='f')) c-='A'-10;
s[i]=c;
}
ll=((l*1234)>>10); // num of decimals to compute
for (cy=0,i=1;i<=ll;i++)
{
for (cy=0,j=l;j>=1;j--)
{
val=s[j];
val*=10;
val+=cy;
s[j]=val&15;
cy=val>>4;
}
dec+=char(cy+'0');
for (;;)
{
if (!l) break;;
if (s[l]) break;
l--;
}
if (!l) break;;
}
}
return dec;
}
//---------------------------------------------------------------------------
AnsiString pi_BBP() // https://en.wikipedia.org/wiki/Bailey–Borwein–Plouffe_formula
{
const int N=100; // 32*N bit uint arithmetics
int sh;
AnsiString s;
uint<N> pi,a,b,k,k2,k3,k4;
for (pi=0,sh=(N<<5)-8,k=0;sh>=0;k++,sh-=4)
{
k2=k*k;
k3=k2*k;
k4=k3*k;
a =k2* 120;
a+=k * 151;
a+= 47;
b =k4* 512;
b+=k3*1024;
b+=k2* 712;
b+=k * 194;
b+= 15;
a<<=sh;
pi+=a/b;
}
pi<<=4;
s=pi.strhex();
s=s.Insert(".",2);
return str_hex2dec(s);
}
//---------------------------------------------------------------------------
The code is using VCL AnsiString which is a self allocating string and mine uint<N> template which is unsigned integer arithmetics of 32*N bitwidth based on mine ALU32. As you can see you only need big integer division addition and multiplication for this (all the other stuff is doable on normal integers).
Here decadic result versus 1000 digit Pi reference:
ref: 3.1415926535897932384626433832795028841971693993751058209749445923078164062862089986280348253421170679821480865132823066470938446095505822317253594081284811174502841027019385211055596446229489549303819644288109756659334461284756482337867831652712019091456485669234603486104543266482133936072602491412737245870066063155881748815209209628292540917153643678925903600113305305488204665213841469519415116094330572703657595919530921861173819326117931051185480744623799627495673518857527248912279381830119491298336733624406566430860213949463952247371907021798609437027705392171762931767523846748184676694051320005681271452635608277857713427577896091736371787214684409012249534301465495853710507922796892589235420199561121290219608640344181598136297747713099605187072113499999983729780499510597317328160963185950244594553469083026425223082533446850352619311881710100031378387528865875332083814206171776691473035982534904287554687311595628638823537875937519577818577805321712268066130019278766111959092164201989
BPP: 3.14159265358979323846264338327950288419716939937510582097494459230781640628620899862803482534211706798214808651328230664709384460955058223172535940812848111745028410270193852110555964462294895493038196442881097566593344612847564823378678316527120190914564856692346034861045432664821339360726024914127372458700660631558817488152092096282925409171536436789259036001133053054882046652138414695194151160943305727036575959195309218611738193261179310511854807446237996274956735188575272489122793818301194912983367336244065664308602139494639522473719070217986094370277053921717629317675238467481846766940513200056812714526356082778577134275778960917363717872146844090122495343014654958537105079227968925892354201995611212902196086403441815981362977477130996051870721134999999837297804995105973173281609631859502445945534690830264252230825334468503526193118817101000313783875288658753320838142061717766914730359825349042875546873115956286388235378759375195778185778048187
The computed bigint value is exported to hex string and then converted to decadic base using str_hex2dec from link above. The number of iterations depends on the target bitwidth.
The code is not optimized yet...
What about implementing 32 bits arithmetic ?
For an addition, add the two high order words (16 bits), then the two low order words, test the overflow bit, and carry to the high order result if necessary.
If you can predict when overflow will occur, you can switch from 16 to 32 bits arithmetic when necessary.
Testing the overflow bit cannot be done in pure C, it will require some inline assembly or an intrinsic function.
Otherwise, you can be inspired by this answer: https://codereview.stackexchange.com/a/37178/39646
There is a trick:
Consider using an array for the numerators and another array for the denominators. Each position would represent the number of times that number is multiplied to get the actual number.
An example:
(1 * 2 * 3 * 7 * 7) / (3 * 6 * 8)
Would be represented as:
num[] = {1, 1, 1, 0, 0, 0, 2};
denom[] = {0, 0, 1, 0, 0, 1, 0, 1};
Then consider factorizing into prime numbers every number before storing it, so that you have lower numbers. Now you will need another array to store all the primes:
primes[] = {2, 3, 5, 7};
num[] = {1, 1, 0, 2};
denom[] = {4, 2, 0, 0};
This will allow you to store unimaginably big numbers, but you will sooner or later want to transform them back into numbers, so you will want to simplify this first. The way to do it is just subtract factors[i] += num[i] - denom[i] for every field in the arrays, for every fraction in the series. You will want to simplify after each iteration, so you minimize overflow risk.
factors[] = {-3, -1, 0, 2};
When you need the number, just do num *= pow(primes[i], factors[i]); if the factor is positive, or num /= pow(primes, -factors[i]); if it is negative, for every field in the arrays. (Do nothing if it is 0.
num and denom are temporary arrays used to store a fraction, the array where the result is being stored is factors. Remember to memset the temporary arrays before every use.
This explanation is useful for any big fraction. To adapt it to your specific problem, you may need to use an integer power function, and also multiply by 10^something to turn the decimal part into an integral part. That is your mission, should you accept it :)
Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 6 years ago.
Improve this question
I am using this code to create; but all the results are in range of 10 to 32000.
Can you tell me what I am doing wrong?
for (i = 0; i < N; i++) {
*(A + i) = rand() % (1000000000 - 10 + 1) + 10;
printf("%lu\n", *(A + i));
}
rand() returns a value in the range of 0 and RAND_MAX (which, according to the standard, is at least 32767): https://www.tutorialspoint.com/c_standard_library/c_function_rand.htm
If you want a higher value you can multiply multiple rand() results.
1,000,000,000 (3B9ACA00) is a 30-bit number.
rand() generates results in the [0...RAND_MAX] range. RAND_MAX may be as small as 32,767, a 15-bit number// RAND_MAX may be as large as INT_MAX. Multiple calls to rand() are needed when RAND_MAX < (1000000000 - 10 + 1), the number of different values sought by OP.
The below throws out small or larges values (about 7% of the time) and tries again. This is done to maintain a fair distribution of numbers.
uint32_t rand_10_to_1000000000(void) {
// This method only works well when RAND_MAX is 2**n -1.
// This is commonly true
assert((RAND_MAX + (uint32_t) 1) & RAND_MAX == 0);
uint32_t r;
do {
r = rand();
#if RAND_MAX < 0x3FFFFFFF
// Adding 1 to RAND_MAX as an int should be avoided to prevent int overflow.
r *= RAND_MAX + (uint32_t) 1;
r += rand();
#endif
r &= 0x3FFFFFFF; // only use lower 30 bits.
} while (r < 10 || r > 1000000000);
return r;
}
Here is what documentation says about rand() return value:
An integer value between 0 and RAND_MAX.
And here is what documentation says about RAND_MAX:
This value is library-dependent, but is guaranteed to be at least 32767 on any standard library implementation.
So in your implementation RAND_MAX can probably generate numbers up to 32767. You probably have to generate upper and lower bits independently like:
int big_rand()
{
return rand() | (rand() << 15);
}
Your system's implementation of rand() has limited precision. The standard mandates that RAND_MAX be at least 32767. You system seems to use this minimum value.
You can combine multiple random values to compute your samples:
for (i = 0; i < N; i++) {
A[i] = 10 + (rand() | ((unsigned)rand() << 15)) % (1000000000 - 10 + 1);
printf("%lu\n", A[i]);
}
PS: why do you write *(A+i) instead of the more readable A[i]?
Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 6 years ago.
Improve this question
Problem statement:
Find the sum of all the multiples of 3 or 5 below N.
Input Format:
First line contains T that denotes the number of test cases. This is followed by T lines, each containing an integer,N.
Constraints :
1 <= T <= 10^5
1 <= N <= 10^9
Output Format:
For each test case, print an integer that denotes the sum of all the multiples of 3 or 5 below N.
This is my code :
#include <stdio.h>
int main() {
long t,i,x;
scanf("%ld",&t);
long y[t];
for(i=0; i<t; i++) {
scanf("%ld",&x);
long j,k,sum= 0;
if(x<=3)
sum= 0;
else if(x<=5)
sum= 3;
else {
for(j=3; j<x; j+=3)
sum= sum + j;
for(j=5; j<x; j+=5)
if(j%3!=0)
sum = sum + j;
}
y[i] = sum;
}
for(i=0; i<t; i++) {
printf("%ld\n",y[i]);
}
return 0;
}
There is a solution with a time complexity of O(T):
Use the formula for sum of integers 1+2+3+...+n = n*(n+1)/2.
Also note that 3+6+9+...+(3*n) = 3*(1+2+3+...+n) = 3*n*(n+1)/2.
Figure out how many numbers divisible by 3 there are. Calculate their sum.
Figure out how many numbers divisible by 5 there are. Calculate their sum.
Figure out how many numbers divisible by 15 (=3*5) there are. Calculate their sum.
Total sum is sum3 + sum5 - sum15. The numbers divisible by both 3 and 5 (hence by 15) are both in sum3 and in sum5, so unless we subtract sum15 they would be counted twice.
Note that the sum will overflow a 32 bit integer, so make sure you use a 64 bit integer type.
You can achieve constant complexity if you employ the Ancient Power of Mathematics.
First figure out how many numbers divisible by three there are.
Compute their sum.
(You do not need any loops for this, you only need elementary arithmetic.)
Repeat for five and fifteen.
The total is a simple expression involving those three sums.
The details left as an exercise for the reader.
I am a beginner in C and wish to know how to convert an array of numbers that represent the bits of a number into the integer it represents.
I searched online but only found char array to int.
I am making converter and need to int array to toggle the bit values from 1 to 0 and vice versa(ie binary). So far i have managed to make the array integers toggle, but I cannot figure out how to change the array of numbers into the single number the array represents. I need this integer so i can convert it into a decimal number which the user can view.
Is there any simple solution to this?
bin= integer variable to store the binary number
arrbin = integer array to store the state of the bit ie(00000000)
for (i = 0; i < 8; ++i )
{
bin = bin + (10 * arrbin[i]);
}
EDIT: I think i see the problem now, instead of the values being implemented every exponent of 10 up, the numbers were only being multiplied by 10. will try and see if this fixes it.
EDIT #2: I dont mean conversion of binary to decimal. I meant conversion of array of numbers ie{1,0,0,0,0,0,0,1) to integer (integer varible = 10000001 not 129)
You basiclly have the answer but you would be better doing it from the other direction ie:
int multiplier = 1;
for (i = 7; i >= 0; --i )
{
bin += (multiplier * arrbin[i]);
multiplier *= 10;
}
that way you can change the length of the array you are using easily.
How about do it manually, the same way you do it to convert binary to int using powers of 2
#include <stdio.h>
#include <string.h>
main()
{
int arr[4]={1,0,0,1};
int i;
int output=0, power=1;
for (i=0; i<4; i++)
{
output += arr[3-i]*power;
power *= 2;
}
printf("%d\n", output);
in this example
arr = 1 0 0 1
output = 1*2^0 + 0*2^1 + 0*2^2 + 1*2^3 = 9
You're forgetting that binary doesn't work by multiplying the value by 10, but by 2 (multiplying by 10 would be good it you're converting a decimal number to an int, but there are already functions for that).
So if I take your code and apply the appropriate multiplication:
for (bin = 0, i = 0; i < 8; ++i )
{
bin *= 2;
bin = bin + arrbin[i];
}
Instead of multiplying by 2 the value of bin, you can use bitshifts instead (replace bin *= 2; with bin = bin << 1;).
All this supposes that the arrbin array contains valid values, and not, for example, ASCII characters of the values. If this is the case, you will have to convert it to a valld value before adding it to bin.
I had to use this method to convert my binary array to a decimal integer. These other solutions didn't work for me, perhaps my array wasn't setup the same but either way, here is my answer to this question.
int bin_to_int_digit(int* in, int length)
{
int exp = 0;
int i;
int bin = 0;
for (i = length - 1; i >= 0; i--)
{
bin += in[i] * pow(2, exp);
exp += 1;
}
return bin;
}
This subroutine requires the use of the math.h header so make sure you include -lm flag when compiling with gcc or else you will get an error.
I was trying to solve a problem using C on project euler click here
Here is the code. It works fine for 10 values but for 1000 values it gives a wrong output. I noticed that it gives a right output till 32. I think I'm exceeding the memory or something. How do I allocate memory for such a large array?
#include <stdio.h>
int main() {
int a[10], i, sum=1, b=0;
for(i = 1; i < 10; i++) {
a[0] = 1;
a[i] = sum + a[i-1];
sum = sum + a[i-1];
}
for(int j = 1;j > 0; j++) {
b = b + sum%10;
if(sum<10)
break;
sum = sum/10;
}
printf("%d\n",b);
return 0;
}
You might try computing 21000 as an 80-bit long double, then using sprintf to convert it to a string, then summing the digits of that string.
Why this works:
Floating-point types store numbers as a mantissa times an exponent. The exponent is always a power of two, and the mantissa can be 1. For a long double, the exponent can be up to 216383. printf and friends, on modern implementations, will correctly print out the digits of a floating-point number.
Code:
int main() {
char buf[1024]; int ans = 0;
sprintf(buf, "%.0f", 0x1.0p1000);
for (int i = 0; buf[i]; i++) ans += buf[i] - '0';
printf("%i\n", ans);
}
I noticed that it gives a right output till 32
That is, because the integer type you're using has 32 bits. It simply can't hold larger numbers. You can't solve it the conventional way.
Here's what I'd suggest: First let's estimate how many digits that number will have. Every time a number gets 10-fold in decimal writing a new digit is required. So the number of digits for a number in decimal is given by ceil(log10(n)). So for 2^1000 you need ceil(log10(2^1000)) digits, but that is just ceil(1000*log10(2)) = 302, so you'll need 302 decimal digits to write it down.
This gives the next idea: Write down the number 1 in 302 digits, i.e. 301 times '0' and one '1' in a string. Then double the string 1000 times, by adding it to itself just like in elementary school, carrying the overflowing digits.
EDIT I think I should point out, that the problem encountered is the whole point of this Project Euler problem. Project Euler problems all have in common, that you can not solve them by using naive programming methods. You must get creative to solve them!