I am trying solve the problem posed in this question that asks << 1 operation be performed on a 64 bit number using NAND operation only and without using any arithmetic operation. My attempted solution went as follows :
First I took an 8 bit number, scanned the digits by ANDing with powers of 2s, then shifted the digits leftward by ORring.
#include <stdio.h> #define BIT 8 int main () { unsigned char number = 121, shift = 0, digit; unsigned char power[] = {1, 2, 4, 8, 16, 32, 64, 128, 0}; for (int i = 0; i < BIT+1; i++) { digit = power[i] & number; if (number & digit != 0) {shift = shift | power[i+1];} } printf ("8bit number = %u\nnumber << 1 = %u", number, shift); return 0; }Once it worked I replaced the AND, OR, NOT logic with NAND logic by using the following identities derived by applying Demorgan.
NAND (x, y) = OR (NOT(x), NOT(y))
AND (x, y) = NAND (NAND (x, y), NAND (x, y))
OR (x, y) = NAND (NAND (x, x), NAND (y, y))
Also enabled user input and made sure that it shows that the result of our custom shifter equals the result of the built in shifter.
#include <stdio.h>
#define BIT 8
unsigned char NAND (unsigned char x, unsigned char y)
{
return ~x | ~y;
}
void bitwise_shift (unsigned char * input, unsigned char * output)
{
*output = *input << 1;
}
void nand_shift (unsigned char * input, unsigned char * output)
{
unsigned char digit, power[] = {1, 2, 4, 8, 16, 32, 64, 128, 0};
*output = 0;
for (int i = 0; i < BIT+1; i++)
{
digit = NAND (NAND (*input, power[i]), NAND (*input, power[i]));
if (NAND (NAND (*input, digit), NAND (*input, digit)) != 0)
{
*output = NAND (NAND (*output, *output), NAND (power[i+1], power[i+1]));
}
}
}
int main ()
{
while (1)
{
unsigned char number, nand_shifted, bitwise_shifted;
printf ("Give me an 8-bit number x = ");
int temp = scanf ("%u", &number);
if (temp != 1 | temp == EOF) {break;}
nand_shift (&number, &nand_shifted);
bitwise_shift (&number, &bitwise_shifted);
printf ("x << 1 = %u\nx x << 1 (NAND) = %u\n\n", bitwise_shifted, nand_shifted);
}
printf ("!!ERROR!!");
return 0;
}
Once it worked I attempted to extend it to 64-bit. I changed all the
unsigned chartypes tounsigned long longtypes and calculated the powers of 2's array (now containing 65 element) by running this side programme and copy pasting its output into the main program.#include <stdio.h> #define BIT 64 void generate_power_array () { int base = 2, exponent = BIT-1; unsigned long long power = 1; printf ("power[] = {1"); for (int i = 1; i <= exponent; i++) { power *= base; printf (", %llu", power); } printf (", 0};"); } int main () { generate_power_array (); }I ended up with the following which works but gives this- "warning: integer constant is so large that it is unsigned".
#include <stdio.h> #define BIT 64 unsigned long long NAND (unsigned long long x, unsigned long long y) { return ~x | ~y; } void bitwise_shift (unsigned long long * input, unsigned long long * output) { *output = *input << 1; } void nand_shift (unsigned long long * input, unsigned long long * output) { unsigned long long power[] = {1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048, 4096, 8192, 16384, 32768, 65536, 131072, 262144, 524288, 1048576, 2097152, 4194304, 8388608, 16777216, 33554432, 67108864, 134217728, 268435456, 536870912, 1073741824, 2147483648, 4294967296, 8589934592, 17179869184, 34359738368, 68719476736, 137438953472, 274877906944, 549755813888, 1099511627776, 2199023255552, 4398046511104, 8796093022208, 17592186044416, 35184372088832, 70368744177664, 140737488355328, 281474976710656, 562949953421312, 1125899906842624, 2251799813685248, 4503599627370496, 9007199254740992, 18014398509481984, 36028797018963968, 72057594037927936, 144115188075855872, 288230376151711744, 576460752303423488, 1152921504606846976, 2305843009213693952, 4611686018427387904, 9223372036854775808, 0}; unsigned long long digit; *output = 0; for (int i = 0; i < BIT+1; i++) { digit = NAND (NAND (*input, power[i]), NAND (*input, power[i])); if (NAND (NAND (*input, digit), NAND (*input, digit)) != 0) { *output = NAND (NAND (*output, *output), NAND (power[i+1], power[i+1])); } } } int main () { while (1) { unsigned long long number, nand_shifted, bitwise_shifted; printf ("Give me a 64-bit number x = "); int temp = scanf ("%llu", &number); if (temp != 1 | temp == EOF) {break;} nand_shift (&number, &nand_shifted); bitwise_shift (&number, &bitwise_shifted); printf ("x << 1 = %llu\nx << 1 (NAND) = %llu\n\n", bitwise_shifted, nand_shifted); } printf ("!!ERROR!!"); return 0; }
But if I do the same for 32-bit numbers, by changing all the unsigned char types to unsigned int types and by calculating the powers of 2s array using the aforementioned side programme, I get the following, which works fine and gives no warning.
#include <stdio.h>
#define BIT 32
unsigned int NAND (unsigned int x, unsigned int y)
{
return ~x | ~y;
}
void bitwise_shift (unsigned int * input, unsigned int * output)
{
*output = *input << 1;
}
void nand_shift (unsigned int * input, unsigned int * output)
{
unsigned int power[] = {1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048, 4096, 8192, 16384, 32768, 65536, 131072, 262144, 524288, 1048576, 2097152, 4194304, 8388608, 16777216, 33554432, 67108864, 134217728, 268435456, 536870912, 1073741824, 2147483648, 0};
unsigned int digit;
*output = 0;
for (int i = 0; i < BIT+1; i++)
{
digit = NAND (NAND (*input, power[i]), NAND (*input, power[i]));
if (NAND (NAND (*input, digit), NAND (*input, digit)) != 0)
{
*output = NAND (NAND (*output, *output), NAND (power[i+1], power[i+1]));
}
}
}
int main ()
{
while (1)
{
unsigned int number, nand_shifted, bitwise_shifted;
printf ("Give me an 8-bit number x = ");
int temp = scanf ("%u", &number);
if (temp != 1 | temp == EOF) {break;}
nand_shift (&number, &nand_shifted);
bitwise_shift (&number, &bitwise_shifted);
printf ("x << 1 = %u\nx x << 1 (NAND) = %u\n\n", bitwise_shifted, nand_shifted);
}
printf ("!!ERROR!!");
return 0;
}
So, I have one solution for 3 situations. For 8-bit it works, for 32-bit it works, for 64-bit it works but gives this- "warning: integer constant is so large that it is unsigned". Where is this warning originating from and how can it be gotten rid of?
2147483648is too large for anint. You can make it unsigned with ausuffix.2147483648u.9223372036854775808, not2147483648return ~(x & y)would be the "correct" implementation.