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 char types to unsigned long long types 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?
A decimal integer constant without any suffix is always considered a signed type.
As the number 9223372036854775808 is greater than the largest 64-bit signed integer, the compiler cannot determine a type in accordance with the C standard.
It seems your compiler instead decides to assign it an unsigned type and gives you a warning that something non-standard is going on.
By adding the suffix u like 9223372036854775808u the warning goes away as the type is now unsigned per standard.
In your case I would recommend using hex values instead, like 0x8000000000000000. Hex integer constants automatically get an unsigned type if they are greater than the maximum signed value for a given width and your program will be easier to read and understand.
Based on the feedback provided by other members it appears there are 2 ways to solve this problem. 1) use hexadecimal, which can be implemented by changing the last entry of the unsigned long long power[] array in the void nand_shift () function from decimal 9223372036854775808 to hexadecimal 0x8000000000000000, so that the programme looks like this :
#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, 0x8000000000000000, 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;
}
An alternative option 2) is to use the suffix u after every number in the power[] array so that it becomes explicitly stated that these numbers are unsigned. This solution can be implemented in the following way :
Rewrite the generate_power_array () function in a manner such that all numbers have a u suffix attached to them, explicitly stating to the compiler that these numbers are unsigned.
#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 ("u, %llu", power);
}
printf ("u, 0u};");
}
int main ()
{
generate_power_array ();
}
Copy paste the output of the generate_power_array () function to initialize the unsigned long long power[] array in the void nand_shift () function. The rest of the programme remains unchanged.
#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[] = {1u, 2u, 4u, 8u, 16u, 32u, 64u, 128u, 256u, 512u, 1024u, 2048u, 4096u, 8192u, 16384u, 32768u, 65536u, 131072u, 262144u, 524288u, 1048576u, 2097152u, 4194304u, 8388608u, 16777216u, 33554432u, 67108864u, 134217728u, 268435456u, 536870912u, 1073741824u, 2147483648u, 4294967296u, 8589934592u, 17179869184u, 34359738368u, 68719476736u, 137438953472u, 274877906944u, 549755813888u, 1099511627776u, 2199023255552u, 4398046511104u, 8796093022208u, 17592186044416u, 35184372088832u, 70368744177664u, 140737488355328u, 281474976710656u, 562949953421312u, 1125899906842624u, 2251799813685248u, 4503599627370496u, 9007199254740992u, 18014398509481984u, 36028797018963968u, 72057594037927936u, 144115188075855872u, 288230376151711744u, 576460752303423488u, 1152921504606846976u, 2305843009213693952u, 4611686018427387904u, 9223372036854775808u, 0u};
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;
}
In these ways there will be no error &/ warnings.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With