I am currently implementing a code that runs Fibonacci sequence (up to the 60th number) in riscv32I, which means that the memory address that I can use only has 32bits.
I have first implemented the code in C, and then in Assembly, but I am curious if the algorithm I used has a name so I can do more research. The code is as such,
#include <stdint.h>
#include <stdio.h>
#include <inttypes.h>
int main() {
uint32_t n1 = 0; // first pre number (n - 2)
uint32_t n2 = 1; // second pre number (n - 1)
uint32_t add = 0; // current number
uint32_t store_hi = 0;
uint32_t store_lo = 0;
uint32_t result; // result
uint32_t carry; // carry bit
for (int i = 2; i < 61; i++) {
carry = 0; // reset carry bit
add = (uint32_t)(n2 + n1); // calculate current fib number
if (add < n1) { // if overflow
carry = 1; // set carry bit
}
result = store_hi + store_lo; // keeping track of higher bits
result = result + carry; // add carry bit
store_lo = store_hi; //
n1 = n2; // update first pre number
store_hi = result; //
n2 = add; // update second pre number
}
printf("Result32: 0x%08" PRIx32 " 0x%08" PRIx32 "\n", result, add);
uint64_t result64 = ((uint64_t)result << 32) | add;
printf("Result64: 0x%016" PRIx64 " -> %" PRId64 "\n", result64, result64);
}
Running the code gives
Result32: 0x00000168 0x6c8312d0
Result64: 0x000001686c8312d0 -> 1548008755920
The basic concept is that because the Fibonacci number gets too big to fit within a single 32bit memory address, we have to split it into 32bit memory address, one holding the upper bit, and one holding the lower bit.
Let's generalize the above algorithm to a 4 bit memory space, to make it easier to follow the algorithm. This means that the maximum int can be 16. Let ss set n1 = 10, n2 = 10.
Loop 1:
add = 4 # (10 + 10 = 20, but overflow, so 20 % 16 = 4)
carry = 1
result = 1
store_lo = 0
store_hi = 1
n1 = 10
n2 = 4
# output: 0x14, 0x1 hi bit, 0x4 lo bit, which is 10 + 10 = 20
Loop 2:
add = 14
carry = 0
result = 1
store_lo = 1
store_hi = 1
n1 = 4
n2 = 14
# output: 0x1e, 0x1 hi bit, 0xe or 14, lo bit, which is 10 + 20 = 30
loop 3:
add = 2 (14 + 4 = 18, but overflow, so 18 % 16, 2)
carry = 1
result = 3
store_lo = 1
store_hi = 2
n1 = 14
n2 = 2
#output: 0x32, 0x3 hi bit, 0x2 low bit, which is 20 + 30 = 50
.... and so on.
This should work for any base, but I am curious what this algorithm is denoted as, or if it is simply related to modules and powers?
Thanks!
It's called Arbitrary-precision arithmetic, you can read more about it here.
Arbitrary-precision arithmetic, also called bignum arithmetic, multiple-precision arithmetic, or sometimes infinite-precision arithmetic, indicates that calculations are performed on numbers whose digits of precision are limited only by the available memory of the host system.
One of the troubles of venturing from 32-bit to 64-bit is that the now distant horizon rapidly becomes as constraining as the former, "closer" horizon was.
Below is a sketch of an "ASCII digit" Fibonacci calculator. Its two seeds are "0" and "1" at the right end of two 20 character buffers. (20 is arbitrary, but takes one beyond the 60th value in the Fibonacci sequence.) This could be optimised and improved in a hundred different ways. It is a "powers of ten" version that uses two ASCII strings for its storage. One could, if one was patient, use 1000 character buffer, or 10,000 to go deep into the Fibonacci realm...
I hope you find this interesting.
EDIT: #Chux has pointed out that the sequence generated below indexes from 1, whereas indexing from 0 is correct. The simple fix (not shown here) would be to change three instances of ++fn to fn++ (an exercise left to the reader.) Thank you again, #Chux!
#include <stdio.h>
int main() {
char f[2][20 + 1], *fmt = "%s %-3d";
int fn = 0;
sprintf( f[0], "%20s", "0" );
sprintf( f[1], "%20s", "1" );
printf( fmt, f[ 0 ], ++fn );
putchar( '\n' );
printf( fmt, f[ 1 ], ++fn );
for( bool evod = false; getchar() != EOF; evod = !evod ) {
for( int carry = 0, i = 20; --i >= 0; ) {
if( f[ evod][i] == ' ' && f[!evod][i] == ' ' && carry == 0 ) break;
int f1 = f[ evod][i] == ' ' ? 0 : f[ evod][i] - '0';
int f2 = f[!evod][i] == ' ' ? 0 : f[!evod][i] - '0';
f1 += f2 + carry; carry = f1 / 10; f[ evod][i] = f1%10 + '0';
}
printf( fmt, f[ evod], ++fn );
}
return 0;
}
Output
0 1
1 2
1 3
2 4
3 5
5 6
8 7
13 8
21 9
/* omitted */
591286729879 59
956722026041 60
1548008755920 61
2504730781961 62
4052739537881 63
Related
I want to multiply every other digit by 2, starting with the number’s second-to-last digit, and then add those products’ digits together, but the first printed values seem completely nonsensical.
#include <stdio.h>
#include <math.h>
int len(long li);
int main(void)
{
// Get credit card number
long credit_card = 378282246310005;
// Adding every second digit's double's digits, starting with the second to last
int sum = 0;
int digit_doubled;
for (int i = 0; i < len(credit_card); i++)
{
if (i % 2 == 0)
{
continue;
}
digit_doubled = (int) (credit_card / pow(10, i)) % 10 * 2;
printf("Digit doubled %i: %i\n", i, digit_doubled);
for (int j = 0; j < len(digit_doubled); j++)
{
sum += (int) (digit_doubled / pow(10, j)) % 10;
}
}
}
int len(long li)
{
if (li == 0)
{
return 1;
}
return floor(log10(li)) + 1;
}
I have tried modifying the expression to see what results I'd get. When I deleted the
% 10 * 2 from the end of digit_doubled = (int) (credit_card / pow(10, i)) % 10 * 2;, I got results that indicate some kind of integer overflow, but I have absolutely no idea where it could be coming from since my program isn't really producing any high values anywhere.
Having suggested using a LUT to deliver the single digit value required by the OP's question, here is a snippet of code to do just that:
unsigned long long copy = longValue; // perhaps correct on OP's compiler??
copy /= 10; // dispose of the checksum digit (rightmost)
// The following line depends on the OP's problem statement
// Is this digit odd (checksum digit being digit zero)
// or is this digit even? (checksum digit being disregarded.)
// Incl-/excl- next line to suit problem statement.
copy /= 10; // dispose of the rightmost "odd" digit
while( copy ) {
int digit = copy % 10; // get "even" digit from the right end.
// Crafted LUT to return correctly "doubled & folded" value of this digit.
sum += "0246813579"[digit] - '0';
copy /= 100; // "shift" value down by 100 (ie: 2 digits of value)
}
I leave it as an exercise for the OP to determine what characterises "even" and "odd" in the sequence of digits of a credit card "number". Does one count the checksum digit as '1' or not? For the OP to work out...
For fun, here's the loop after compaction.
for( /**/; copy; copy /= 100 )
sum += "0246813579"[ copy % 10 ] - '0';
And, a more advanced version would simply calculate the desired value from the supplied value:
for( /**/; copy; copy /= 100 )
sum += copy%5 * 2 + copy%10/5;
For those who (reasonably) question the validity of the formula above:
#include <stdio.h>
int main( void ) {
for( int i = 0; i < 10; i++ ) {
int j = 2 * i;
printf( "Digit Value: %d ", i );
printf( " x2 = %02d ", j );
printf( "==> %d + %d ", j/10, j%10 );
printf( "==> %d ", j/10 + j%10 );
printf( "==== %d\n", i%5 * 2 + i%10/5 ); // <== Formula version
}
return 0;
}
Digit Value: 0 x2 = 00 ==> 0 + 0 ==> 0 ==== 0
Digit Value: 1 x2 = 02 ==> 0 + 2 ==> 2 ==== 2
Digit Value: 2 x2 = 04 ==> 0 + 4 ==> 4 ==== 4
Digit Value: 3 x2 = 06 ==> 0 + 6 ==> 6 ==== 6
Digit Value: 4 x2 = 08 ==> 0 + 8 ==> 8 ==== 8
Digit Value: 5 x2 = 10 ==> 1 + 0 ==> 1 ==== 1
Digit Value: 6 x2 = 12 ==> 1 + 2 ==> 3 ==== 3
Digit Value: 7 x2 = 14 ==> 1 + 4 ==> 5 ==== 5
Digit Value: 8 x2 = 16 ==> 1 + 6 ==> 7 ==== 7
Digit Value: 9 x2 = 18 ==> 1 + 8 ==> 9 ==== 9
In the first loop when i=1 you cast a value greater than the maximum value that can be stored in an integer (2147483647) which cause it to be truncated and on my system go negative:
digit_doubled = (int) (credit_card / pow(10, i)) % 10 * 2; // =>
digit_doubled = (int) 37828224631000 % 10 * 2; / =>
digit_doubled = -1847312168 % 10 * 2; // =>
digit_doubled = -16;
I suggest you include stdint.h and use uint64_t instead of silently assume that a long is 64 bit. Alternatively, consider using a string as a credit number is an identifier not a number (even though it is written as one).
Mixing functions that operate on double for integer type values will open you up to floating point rounding errors. You could use uint64_t versions of these functions instead of double. Below I implemented a len() and my_pow10() functions for you. As the value of digit_doubled is at most 18 you can just inline that calculation instead of using a loop.
#include <stdio.h>
#include <stdint.h>
uint64_t my_pow10(uint64_t x) {
if(x == 0) return 1;
size_t v = 10;
for(size_t i = 1; i < x; i++, v *= 10);
return v;
}
size_t len(uint64_t v) {
size_t i = 0;
for(; v; i++, v /= 10);
return i;
}
int main(void) {
const uint64_t credit_card = 378282246310005;
const uint8_t credit_card_len = len(credit_card);
uint8_t sum = 0;
for (uint8_t i = 1; i < credit_card_len; i += 2) {
uint8_t digit_doubled = credit_card / my_pow10(i) % 10 * 2;
printf("Digit doubled %hhu: %hhu\n", i, digit_doubled);
sum += digit_doubled / 10 + digit_doubled % 10;
}
printf("sum = %u\n", sum);
}
You don't need floating-point arithmetic at all here, or logs or pows. You can use % 10 to extract the next digit, and / 10 to discard it. Like this:
#include <stdint.h>
#include <stdio.h>
int main(void)
{
uint64_t credit_card = 378282246310005ULL;
int sum = 0;
while (credit_card != 0)
{
credit_card /= 10; // Discard rightmost digit
int double_digit = 2 * (credit_card % 10);
credit_card /= 10;
sum += double_digit % 10;
double_digit /= 10;
sum += double_digit % 10;
}
printf ("%d\n", sum);
}
I have been trying to translate this code to put it in simple terms to understand but can't quite get it.
Can someone help me understand it better and why the next line would they want to divide by 16?
char r = (c+n1+n2)>=16 ?
((c+n1+n2)-16+'0') :
((c+n1+n2)>9?((c+n1+n2)+55):(c+n1+n2)+'0');
c = (c+n1+n2)/16;
the lines above this are a while loop to print multiple numbers and are:
int i=s1-1, j=s2-1, c=0, k=0;// sets up for the calculations -1
// for the s1 and s2 because you do not want null character included here
// k is the number of places we use for addition
printf("COL d d c\n");
while(i>=0 || j>=0){
int n1 = i<0?0:num1[i]-'0';// is converting from the character representation
// of a number to the actual integer value of the same digit if not 0
int n2 = j<0?0:num2[j]-'0';
char r = (c+n1+n2)>=16 ?
((c+n1+n2)-16+'0') :
((c+n1+n2)>9?((c+n1+n2)+55):(c+n1+n2)+'0');
c = (c+n1+n2)/16;
printf("%3d : %d+%d+%d = %c\n", k, n1, n2, c, r);
i--;
j--;
k++;
}
It seems, the function above was intended to add two hex strings. I believe this, because the line in question encodes hex characters and the overflow, that occurs when adding two digits is treated in a way, that makes only sense if the digits are treated as 4 bit digts (hex digits). E.g. because of the division by 16.
If I am right, the hex decoding contains a bug, while the hex encoding for outputting the result seems almost correct. Almost, because if I got it right, the original version will not be able to calculate string additions like "00F" + "00F" correctly (see last output below).
It seems, as if even the original author was overwhelmed by his code.
Here is a version, that should do, what the original author intended to do:
void string_add(char num1[], char num2[], int s1, int s2) {
int i=s1-1, j=s2-1, c=0, k=0;// sets up for the calculations -1 for the s1 and s2 because you do not want null character included here
int z=0;
// k is the number of places we use for addition
printf("COL d d c\n");
while(i>=0 || j>=0){
/*
* the following lines represent the expressions
* int n1 = i<0?0:num1[i]-'0';// is converting from the character representation of a number to the actual integer value of the same digit if not 0
* int n2 = j<0?0:num2[j]-'0';
* I added the conversion of hex digits in the range A-F
*/
int n1, n2= 0;
char r;
if(i>=0) {
n1= num1[i];
if(n1>='A') {
n1-= 'A'-10;
} else {
n1-= +'0';
}
}
if(j>=0) {
n2= num2[j];
if(n2>='A') {
n2-= 'A'-10;
} else {
n2-= '0';
}
}
/*
* the following code is, what the line
* char r = (c+n1+n2)>=16?((c+n1+n2)-16+'0'):((c+n1+n2)>9?((c+n1+n2)+55):(c+n1+n2)+'0');
* originally did (I also do a partial calculation of the line
* c = (c+n1+n2)/16;
* to avoid repeating the term
*/
c= c+n1+n2;
r= c&15; // only take the lower 4 bits (ignore overflow bits)
z|= r << (4*k);
// construct the binary representation (shift the 4 bits into position and use bitwise or to add them to z)
if(r>9) {
r+= 'A'-10; // produces chars in range A-F = (ascii('G')-16+c
} else {
r+= '0'; // produces chars in range 0-9 if no overflow occurs
}
/*
* now just do the /16 part of
* c = (c+n1+n2)/16;
*/
c/= 16;
printf("%3d : %d+%d+%d = %c\n", k, n1, n2, c, r);
i--;
j--;
k++;
}
printf("%d\n", z);
}
void main(void) {
char s1[]= "0100";
char s2[]= "0B01";
string_add(s1, s2, 4, 4);
}
Tests (first output is from the version above, second from the original version):
"0005"+"0005"=
COL d d c
0 : 5+5+0 = A
1 : 0+0+0 = 0
2 : 0+0+0 = 0
3 : 0+0+0 = 0
10
COL d d c
0 : 5+5+0 = A
1 : 0+0+0 = 0
2 : 0+0+0 = 0
3 : 0+0+0 = 0
"9989"+"0987"=
COL d d c
0 : 9+7+1 = 0
1 : 8+8+1 = 1
2 : 9+9+1 = 3
3 : 9+0+0 = A
41744
COL d d c
0 : 9+7+1 = 0
1 : 8+8+1 = 1
2 : 9+9+1 = 3
3 : 9+0+0 = A
"000F"+"000F"=
COL d d c
0 : 15+15+1 = E
1 : 0+0+0 = 1
2 : 0+0+0 = 0
3 : 0+0+0 = 0
30
COL d d c
0 : 22+22+2 = L
1 : 0+0+0 = 2
2 : 0+0+0 = 0
3 : 0+0+0 = 0
The last output seems suspicuous. Was this really intended?
The code seems to perform the addition of 2 numbers stored as hexadecimal encoded strings. It is obfuscated in silly ways. Here is how to improve readability:
white space should be used wisely to make the logic more obvious: typically insert a space character on both sides of binary operators, between keywords and the corresponding ( and before the { opening a block.
the magic constant 55 should be replaced with 'A' - 10, making it more evident that the code performs a conversion from a numeric value to a hexadecimal digit character.
intermediary values should be computed and stored into aptly named local variables.
comments can be used for non obvious steps.
The code seems incorrect:
c > 0 should be tested too to account for possible overflow on the most significant digit.
conversion from hex should be performed when reading digits from the num1 and num2 strings, converting digits A through F to the values 10 to 15.
the resulting digit would be incorrect if c + n1 + n2 >= 26
Here is an attempt at fixing the code:
// s1 is the length of hex encoded string num1
// s2 is the length of hex encoded string num2
int carry = 0;
int i = s1, j = s2, k = 0;
// k is the number of places we use for addition
printf("COL d d c\n");
while (i > 0 || j > 0 || carry > 0) {
// get the digit values from num1 and num2
char c1 = i == 0 ? '0' : num1[--i];
char c2 = j == 0 ? '0' : num2[--j];
int d1 = c1 <= '9' ? c1 - '0' : c1 - 'A' + 10;
int d2 = c2 <= '9' ? c2 - '0' : c2 - 'A' + 10;
int digit = carry + d1 + d2;
carry = digit >> 4;
digit %= 15;
char r = digit > 9 ? (digit - 10 + 'A') : (digit + '0');
printf("%3d : %d+%d+%d = %c\n", k, d1, d2, carry, r);
k++;
}
So, I have to make a work for college and it consists in creating an algorithm.
The algorithm must find couples of numbers which satisfy a certain condition, which is: the sum from 1 to n (exlusive) results the same as the sum from n+1 to m (inclusive).
At the final, the algorithm must give at least 15 couples.
The first couple is 6 and 8, because from 1 to n (exclusive) (6) is 1+2+3+4+5 = 15 and from n+1 to m is 8+7 = 15.
The algorithm I created is the following one:
int main() {
int count = 0;
unsigned int before = 0;
unsigned int after = 0;
unsigned int n = 1;
unsigned int m = 0;
do {
before += n - 1;
after = n + 1;
for (m = after + 1; after < before; m++) {
after += m;
}
if (before == after) {
printf("%d\t%d\n", n, (m - 1));
count++;
}
n++;
} while (count < 15);
}
This is actually OK, but some of the output are not correct, and its also crap, in terms of complexity, and since I am studying Complexity of Algorithms, it would be good to find some algorithm better than this one.
I also tried doing it in Java, but using int is not good for this problem and using long, it takes hours and hours to compute.
The numbers I have found so far:
6 and 8
35 and 49
204 and 288
1189 and 1681
6930 and 9800
40391 and 57121
The following ones may be incorrect:
100469 and 107694
115619 and 134705
121501 and 144689
740802 and 745928
1250970 and 1251592
2096128 and 2097152
2100223 and 2101246
4196352 and 8388608
18912301 and 18912497
Your results are incorrect beyond the first 6: the range of type unsigned int is insufficient to store the sums. You should use type unsigned long long for before and after.
Furthermore, your algorithm becomes very slow for large values because you recompute after from scratch for each new value of before, with a time complexity of O(N2). You can keep 2 running sums in parallel and reduce the complexity to quasi-linear.
Last but not least, there are only 12 solutions below UINT32_MAX, so type unsigned long long, which is guaranteed to have at least 64 value bits is required for n and m as well. To avoid incorrect results, overflow should be tested when updating after.
Further tests show that the sums after and before exceed 64 bits for values of m around 8589934591. A solution is to subtract 262 from both before and after when they reach 263. With this modification, the program can keep searching for larger values of n and m much beyond 32-bits.
Here is an improved version:
#include <stdio.h>
int main() {
int count = 0;
unsigned long long n = 1;
unsigned long long m = 2;
unsigned long long before = 0;
unsigned long long after = 2;
for (;;) {
if (before < after) {
before += n;
n++;
after -= n;
} else {
m++;
/* reduce values to prevent overflow */
if (after > 0x8000000000000000) {
after -= 0x4000000000000000;
before -= 0x4000000000000000;
}
after += m;
while (before > after) {
after += n;
n--;
before -= n;
}
}
if (before == after) {
printf("%llu\t%llu\n", n, m);
count++;
if (count == 15)
break;
}
}
printf("%d solutions up to %llu\n", count, m);
return 0;
}
Output (running time 30 minutes):
6 8
35 49
204 288
1189 1681
6930 9800
40391 57121
235416 332928
1372105 1940449
7997214 11309768
46611179 65918161
271669860 384199200
1583407981 2239277041
9228778026 13051463048
53789260175 76069501249
313506783024 443365544448
15 solutions up to 443365544448
Your initial brute force program as posted above generates plenty of data for you to analyze. The people in the question's comments recommended the "sum of an arithmetic series" formula instead of your repeated addition, but the fact is that it still would run slow. It's surely an improvement, but it's still not good enough if you want something usable.
Believe it or not, there are some patterns to the values of n and m, which will require some math to explain. I'll be using the functions n(i), m(i), and d(i) = m(i) - n(i) to represent the values of n, m, and the difference between them, respectively, during iteration i.
You found the first six couples:
i n(i) m(i) d(i)
== ====== ====== ======
1 6 8 2
2 35 49 14
3 204 288 84
4 1189 1681 492
5 6930 9800 2870
6 40391 57121 16730
Notice that 6+8 = 14, 35+49 = 84, 204+288 = 492, etc. It so happens that, in the general case, d(i+1) = m(i) + n(i) (e.g. d(2) = m(1) + n(1) = 6 + 8 = 14).
So now we know the following:
d(7)
= n(6) + m(6)
= 40391 + 57121
= 97512
# m(i) = n(i) + d(i)
m(7) = n(7) + 97512
Another way of looking at it since m(i) = n(i) + d(i) is d(i+1) = d(i) + 2n(i):
d(7)
= n(6) + d(6) + n(6)
= d(6) + 2n(6)
= 16730 + 2(40391)
= 97512
d(i) also happens to be useful for computing n(i+1):
n(i+1) = 2d(i+1) + n(i) + 1
n(7) = 2d(7) + n(6) + 1
= 2(97512) + 40391 + 1
= 235416
From there, it's easy to determine things:
i n(i) m(i) d(i)
== ====== ====== ======
1 6 2 8
2 35 14 49
3 204 84 288
4 1189 492 1681
5 6930 2870 9800
6 40391 16370 57121
7 235416 332928 97512
But what about a starting condition? We need a way to find 6 in the first place, and that starting case can be computed by working backward and using substitution:
n(1) = 2d(1) + n(0) + 1
6 = 2(2) + n(0) + 1
5 = 4 + n(0)
1 = n(0)
d(1) = d(0) + 2n(0)
2 = d(0) + 2(1)
2 = d(0) + 2
0 = d(0)
m(0) = n(0) + d(0)
= 1 + 0
= 1
Note that n(0) = m(0) (1 = 1), but it is not a couple. For a pair of numbers to be a couple, the numbers must not be the same.
All that's left is to compute the sum. Since the integers from 1 to n-1 (i.e. 1 to n, excluding n) form an arithmetic series and the series starts at 1, you can use the formula
n(n - 1)
S(n) = --------
2
Below is a program that uses all of this information. You'll notice I'm using a multiplication function mul in place of the multiplication operator. The function's result is used to end the loop prematurely when an unsigned overflow (i.e. wraparound) is encountered. There are probably better ways to detect the wraparound behavior, and the algorithm could be better designed, but it works.
#include <errno.h>
#include <limits.h>
#include <stdio.h>
typedef unsigned long long uval_t;
/*
* Uses a version of the "FOIL method" to multiply two numbers.
* If overflow occurs, 0 is returned, and errno is ERANGE.
* Otherwise, no overflow occurs, and the product m*n is returned.
*/
uval_t mul(uval_t m, uval_t n)
{
/*
* Shift amount is half the number of bits in uval_t.
* This allows us to work with the upper and lower halves.
* If the upper half of F is not zero, overflow occurs and zero is returned.
* If the upper half of (O+I << half_shift) + L is not zero,
* overflow occurs and zero is returned.
* Otherwise, the returned value is the mathematically accurate result of m*n.
*/
#define half_shift ((sizeof (uval_t) * CHAR_BIT) >> 1)
#define rsh(v) ((v) >> half_shift)
#define lsh(v) ((v) << half_shift)
uval_t a[2], b[2];
uval_t f, o, i, l;
a[0] = rsh(m);
a[1] = m & ~lsh(a[0]);
b[0] = rsh(n);
b[1] = n & ~lsh(b[0]);
f = a[0] * b[0];
if (f != 0)
{
errno = ERANGE;
return 0;
}
o = a[0] * b[1];
i = a[1] * b[0];
l = a[1] * b[1];
if (rsh(o+i + rsh(l)) != 0)
{
errno = ERANGE;
return 0;
}
return lsh(o+i) + l;
}
int main(void)
{
int i;
uval_t n = 1, d = 0;
uval_t sum = 0;
#define MAX 15
for (i = 1; i <= MAX; i++)
{
d += n * 2;
n += d * 2 + 1;
sum = mul(n, n - 1) / 2;
if (sum == 0)
break;
printf("%2d\t%20llu\t%20llu\t%20llu\n", i, n, n+d, sum);
}
return 0;
}
This yields 12 lines of output, the last being this one:
12 1583407981 2239277041 1253590416355544190
Of course, if you don't care about the sums, then you can just avoid computing them entirely, and you can find all 15 couples just fine without even needing to check for overflow of a 64-bit type.
To go further with the sums, you have a few options, in order of most to least recommended:
use a "bignum" library such as GNU MP, which is similar to Java's java.math.BigInteger class and which has its own printf-like function for displaying values; if you're on Linux, it may already be available
use your compiler's 128-bit type, assuming it has one available, and create your own printing function for it if necessary
create your own "big integer" type and the associated necessary addition, subtraction, multiplication, division, etc. printing functions for it; a way that allows for easy printing is that it could just be two unsigned long long values glued together with one representing the lower 19 decimal digits (i.e. the max value for it would be 999 9999 9999 9999 9999), and the other representing the upper 19 digits for a total of 38 digits, which is 1038-1 or 127 bits
The fact that the full 15 sums required don't fit in 64 bits, however, makes me concerned that the question was perhaps worded badly and wanted something different from what you wrote.
Edit
To prove this works, we must first establish some rules:
For any values n and m, 0 ≤ n < m must be true, meaning n == m is forbidden (else we don't have a couple, a.k.a. "ordered pair").
n and m must both be integers.
With that out of the way, consider an algorithm for computing the sum of an arithmetic series starting at a and ending at, and including, b with a difference of +1 between each successive term:
(b - a + 1)(b + a)
S(a, b) = ------------------
2
b² - a² + b + a
= ---------------
2
b(1 + b) + a(1 - a)
= -------------------
2
If such a series begins at a=1, you can derive a simpler formula:
b(b + 1)
S(b) = --------
2
Applying this to your problem, you want to know how to find values such that the following is true:
S(n-1) = S(n+1, m)
After applying the arguments, the result looks like this:
(n-1)n m(1 + m) + (n+1)[1 - (n+1)]
------ = ---------------------------
2 2
(n-1)n = m(1 + m) + (n+1)(1 - n - 1)
n² - n = m² + m + (n+1)(-n)
n² - n = m² + m - n² - n
2n² = m² + m
While not important for my purposes, it's perhaps worth noting that m² + m can be rewritten as m(m+1), and the 2n² signifies that one or both of m and m+1 must be divisible by 2. In addition, one must be a perfect square while the other must be twice a perfect square due to the requirement that at least one expression must be divisible by 2. In other words, 2n² = m(m+1) = 2x²y². You can find another equally valid solution using x and y to generate the values of n and m, but I won't demonstrate that here.
Given the equations for n(i+1), m(i+1), and d(i+1):
d(i+1) = d(i) + 2n(i)
= m(i) + n(i)
n(i+1) = 2d(i+1) + n(i) + 1
= 2m(i) + 3n(i) + 1
m(i+1) = d(i+1) + n(i+1)
= 3m(i) + 4n(i) + 1
And the starting conditions:
n(0) = 1
d(0) = 0
m(0) = 1
We can determine whether they actually work by substituting i+2 in place of i in all cases and finding whether we end up with the same equation. Assuming f(n(i)) = 2n²(i) and g(m(i)) = m(i) ⋅ (m(i) + 1), the equation f(n(i+2)) = g(m(i+2)) reduces to f(n(i)) = g(m(i)), proving the equations work for any couple:
f(n(i+2))
= g(m(i+2))
f(2m(i+1) + 3n(i+1) + 1)
= g((3m(i+1) + 4n(i+1) + 1))
2 ⋅ (12m(i) + 17n(i) + 6)²
= (17m(i) + 24n(i) + 8) ⋅ (17m(i) + 24n(i) + 8 + 1)
2 ⋅ (144m²(i) + 408m(i)⋅n(i) + 144m(i) + 289n²(i) + 204n(i) + 36)
= 289m²(i) + 816m(i)⋅n(i) + 289m(i) + 576n²(i) + 408n(i) + 72
288m²(i) + 816m(i)⋅n(i) + 288m(i) + 578n²(i) + 408n(i) + 72
= 289m²(i) + 816m(i)⋅n(i) + 289m(i) + 576n²(i) + 408n(i) + 72
2n²(i)
= m²(i) + m(i)
f(n(i))
= g(m(i))
If you're lost toward the end, I simply subtracted 288m²(i) + 816m(i)⋅n(i) + 288m(i) + 576n²(i) + 408n(i) + 72 from both sides of the equation, yielding 2n²(i) = m²(i) + m(i).
Anwers of Austin Hastings and Michael Burr has solved my problem, this loop is always true as I just realised and it's solved when did it like Austin Hastings did. Cannot mark as answer since it is a comment. Thanks for your help!
I have an assignment in C which is to print only specific kinds of numbers between an 128 and 255 (so 8 digit binary representations) and I should do it without using any arithmetic operators. The conditions are:
Number's binary representation has to have same number of 0's and 1's.
Number's binary representation cannot have more 0's than 1's at any moment when reading from left-to-right. For example, 156 (1001 1100) does not meet the 2nd condition because there are two 0's and only one 1 at the 3rd digit, while 210 (1101 0010) satisfies these conditions.
I am using functional implementation and used a single function for these two conditions and that part of code is:
int checkOneToZero(unsigned int num) {
unsigned int carry = 7,
counterOne = 0,
counterZero = 0,
ct = 0;
while ((carry > 0) || (carry == 0)) {
if ((num >> carry) & 1) {
counterOne = binaryAddition(counterOne, 1);
ct ++;
printf(" %d ", ct);
}
else {
counterZero = binaryAddition(counterZero, 1);
ct ++;
printf(" %d ", ct);
}
carry = binarySubtraction(carry, 1);
printf(" CARRY %d \n", carry);
if (counterZero > counterOne) {
printf(" breakCounterZero %d breakCounterOne %d ", counterZero, counterOne);
return 0;
}
}
printf("successCounterZero = %d successCounterOne = %d", counterZero, counterOne);
if (counterZero == counterOne)
return 1;
return 0;
}
I had wrong output constantly so put some control mechanisms which do not effect the code to track the problem. These are:
ct : Counts how many times it has enter into if or else in while loop.
printf(" CARRY %d \n", carry) : shows carry's value after it has been decreased one.
printf(" breakCounterZero = &d breakCounterOne = %d ") : shows 0 and 1 counts if it has stuck at "if (counterZero > counterOne)" which checks 0 count cannot be higher than 1 count at the end of each while loop.
printf("successCounterZero = %d successCounterOne = %d") : shows if it has passed the while loop.
My problem is if I try to let while loop work until carry is used last with carry = 0, it gives output of 210, which should work as it loops 8 times and at CARRY = -1 it should break from the loop while it is like:
1 CARRY 6
2 CARRY 5
3 CARRY 4
4 CARRY 3
5 CARRY 2
6 CARRY 1
7 CARRY 0
8 CARRY -1
9 CARRY -2
breakCounterZero 5 breakCounterOne 4
so it loops 1 more time than it should and it makes count one more 0 so it fails. But wen I increased limit of carry to 1 in while loop to see what happens, it gives:
1 CARRY 6
2 CARRY 5
3 CARRY 4
4 CARRY 3
5 CARRY 2
6 CARRY 1
7 CARRY 0
successCounterZero = 3 successCounterOne = 4
so it passes the 3rd condition but one less 0 than it should so fails at 2nd condition.
This seems to be a complicated and a too-specific question, but thanks for any hints.
I'm not sure about your binaryAddition and binarySubtraction functions - whether you are required to use them, or simply are using them to meet the condition that no arithmetic operations be used.
For this simple case, it's worth pointing out that you can "count" up to 31 using the bits in an integer. Certainly enough to handle 8 possible values:
int checkOneToZero(unsigned num)
{
unsigned count_0s = 0;
unsigned count_1s = 0;
// Using a 'for' loop here because I know the start, stop, and update.
for (unsigned check_bit = 1 << 7; check_bit; check_bit >>= 1) {
if (num & check_bit) {
/* ++count_1s; */
count_1s |= (count_1s << 1) | 1;
}
else {
/* ++count_0s; */
count_0s |= (count_0s << 1) | 1;
if (count_0s > count_1s) return 0;
}
}
return count_0s == count_1s;
}
i have the recurrence relation of
and the initials condition is
a0 = a1 = 0
with these two, i have to find the bit strings of length 7 contain two consecutive 0 which i already solve.
example:
a2 = a2-1 + a2-2 + 22-2
= a1 + a0 + 20
= 0 + 0 + 1
= 1
and so on until a7.
the problem is how to convert these into c?
im not really good at c but i try it like this.
#include<stdio.h>
#include <math.h>
int main()
{
int a[7];
int total = 0;
printf("the initial condition is a0 = a1 = 0\n\n");
// a[0] = 0;
// a[1] = 0;
for (int i=2; i<=7; i++)
{
if(a[0] && a[1])
a[i] = 0;
else
total = (a[i-1]) + (a[i-2]) + (2 * pow((i-2),i));
printf("a%d = a(%d-1) + a(%d-2) + 2(%d-2)\n",i,i,i,i);
printf("a%d = %d\n\n",i,total);
}
}
the output are not the same as i calculate pls help :(
int func (int n)
{
if (n==0 || n==1)
return 0;
if (n==2)
return 1;
return func(n-1) + func(n-2) + pow(2,(n-2));
}
#include<stdio.h>
#include <math.h>
int main()
{
return func(7);
}
First of uncomment the lines which initialized the 2 first elements. Then at the for loop the only 2 lines need are:
a[i]=a[i-1]+a[i-2]+pow(2, i-2);
And then print a i
In the pow() function, pow(x,y) = x^y (which operates on doubles and returns double). The C code in your example is thus doing 2.0*(((double)i-2.0)^(double)i)... A simpler approach to 2^(i-2) (in integer math) is to use the bitwise shift operation:
total = a[i-1] + a[i-2] + (1 << i-2);
(Note: For ANSI C operator precedence consult an internet search engine of your choice.)
If your intention is to make the function capable of supporting floating point, then the pow() function would be appropriate... but the types of the variables would need to change accordingly.
For integer math, you may wish to consider using a long or long long type so that you have less risk of running out of headroom in the type.