C - number sorting description - c

I have written a C program which sorts an array of 50 of random numbers from 0 - 255. The highest number once sorted is displayed on 8 LEDs as binary digits. The same for the lowest sorted number. I fully understand the program however I need to write up a brief description of it and am struggling with these two functions:
void binaryLowesttNumber()
{
int remainder = lowArray; /* remainder is what I am going to be left with after taking away the value of the pins,
sets remainder as the lowest sorted number */
int j = 128; // value of pins in binary
int i = 7; // index of current pin
while (i >= 0)
{
if (remainder >= j) //if remainder is larger or equal to the value of the current pin
{
digitalWrite(pinArray[i], HIGH);
remainder = remainder - j; // takes value of pin away from remainder
j = j >> 1; // halves the value of j
i--; // moves to next pin
}
else
{
j = j >> 1; // halves the value of j
i--; // moves to next pin
}
}
}
void binaryHighestNumber()
{
int remainder = highArray; // same as binaryLowestNumber function except the remainder will be the highest sorted number
int i = 128;
int thisPin = 7;
while (remainder > 0)
{
while (remainder >= i)
{
double j = i / 2;
digitalWrite(pinArray[thisPin], HIGH);
remainder = remainder - i;
i = i - j;
thisPin--;
}
while (remainder < i)
{
int j = i / 2;
if (j >= 1)
{
i = i - j;
thisPin--;
}
else
{
i = 0;
}
}
}
}

Concentrate on what the function does (not on how it does that, your code explains that). What does function binaryHighestNumber() do? As I understood you correctly, your function sorts an array of 50 of random numbers from 0 - 255 and displays the highest number on 8 LEDs as binary digit. So a perfectly good and informative comment would be:
/**
* Sort an array of 50 random numbers from 0 - 255 and
* display the highest number on 8 LEDs as binary digit using 'digitalWrite()' function.
*/
void binaryHighestNumber()
...
Try to use doxygen format to document your code, that way it will be easy understandable by others who had worked with doxygen. And document what the function does, not how it does that. See Linux kernel coding commenting or GNU coding standard.
EDIT:
I don't see any sorting done in binaryHighestNumber() function. Are you sure this function sorts the array? As I inspect the function definition, all it does is to display a value stored in variable highArray on LEDs. Maybe a better comment would be this:
/**
* Display the highest number obtained from sorting array of 50 elements
* stored in a global variable 'highArray'
* on 8 LEDs as binary digit using 'digitalWrite()' function.
*/
void binaryHighestNumber()
...
EDIT2:
The intent was, that the question is how the code works and now how to comment it, so here we go. Let's concentrate on binaryHighestNumber().
Basically what the function does, is that it sets gpios high which number corresponds to the bit number in highArray. So for a highArray = 0b10101010 we want to light up gpios numbers 7, 5, 3 and 1 (numbering from 0). For highArray = 0b10100101 we want to light up gpios numbers 7, 5, 2 and 0.
The code binaryHighestNumber() keeps track of a remainder - the number substracted from the number of gpios already examined. The other is i - a value that is equal to 2 to the power of currently checked gpio number. thisPin is used to track the gpio number we currently check and it is equal to log2(i).
At first remainder = highArray and i = 128 and we want to check, if we should set gpio number 7 to high. We need to check if bit number 7 in the remainder is set or not. If the remainder is greater then 128, that means that the bit number 7 is set, that means that gpio number 7 needs to be set to high. If bit number 7 is not set, that means that remainder is lower then 128, we don't light the gpio. If the bit number 7 was set, we remove bit 7 from remainder (ie. substract i, which is eqaul to 128, from the remainder) and then bitshift i to the right by dividing it by 2. If bit number 7 was not set, we only bitshift i to the right.
Now remainder = highArray&0b01111111 and i = 64. We continue the process. If the remainder is greater than 64, that means that bit number 6 is set and we need to set gpio number 6 high, remove bit 6 from the remainder (by substracting i from it) and bitshift i to the left (by diving it by 2). If the number is lower then 64, we only bitshift i and continue.
Then remainder = highArray&0b00111111 and i = 32 and we continue until the remainder is equal to zero. (ie. remainder = highArray&0b00000000.
You can simplify the code, to somewhat easier form, like this:
void binaryHighestNumber()
{
int remainder = highArray; // same as binaryLowestNumber function except the remainder will be the highest sorted number
int i = 128;
int thisPin = 7;
while (remainder > 0) {
if (remainder >= i) {
digitalWrite(pinArray[thisPin--], HIGH);
remainder -= i;
i -= i/2;
}
if (remainder < i) {
if (i != 1) {
i -= i/2;
thisPin--;
} else {
i = 0;
}
}
}
}
or maybe like this:
void binaryHighestNumber()
{
int remainder = highArray; // same as binaryLowestNumber function except the remainder will be the highest sorted number
int i = 128;
int thisPin = 7;
while (remainder > 0) {
if (i != 0 && remainder >= i) {
digitalWrite(pinArray[thisPin--], HIGH);
remainder -= i;
i /= 2;
}
if (remainder < i) {
i /= 2;
thisPin--;
}
}
}
Pay attention to that i -= i/2; is not equal to i /= 2;, when i = 1. Also i have removed while loops, they don't change anything. I have removed j variables, they are not needed and don't change anything.
There is a much simpler way to check each bit in a byte and light up these gpios, but I think i will leave that to you to find out.

Related

Binary decimal conversion with arrays

Do you have a simple idea of how we go from a binary number to a decimal number in C without doing any divisions (because I can have very big numbers), maybe only with masks (&, |, << or >>) .
I have a table like this:
tab[20] = {1,0,0,1,0,0,0,1,1,0,0,1,0,0,0,1,1,1,0,1};
and I would like this :
tab[6] = {5,9,6,2,5,3};
Is this something that can be done ? Thank you for your help
idea of how we go from a binary number to a decimal number (can have very big numbers)
For each binary digit, scale the decimal destination by 2 and add the digit.
Pseudo code
some_integer_type tab2[] = {1,0,0,1,0,0,0,1,1,0,0,1,0,0,0,1,1,1,0,1};
some_integer_type tab10[big_enough];
zero fill tab10[]
for (each i element in tab2[] starting with index 0) {
// scale tab10[] by 2 and add tab2[]
carry = tab2[i]
for (each j element in tab10[] starting with the last index) {
sum = (tab10[j] << 1) | carry;
if (sum >= 10) {
sum -= 10;
carry = 1;
} else {
carry = 0;
}
tab10[i] = sum;
}
}
print tab10[]
To do >=, -= 10 with only &, |, << or >>, create helper functions: divide and conquer.
No division and up to 64 bit. This is "big". The bin-to-dec is done with sprintf(). That digit-string can then be converted to an array of integers like your tab[6]
char bittab[64] = {1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0};
long num = 0, dupl = 1;
int i;
for (i = 0; i < sizeof bittab; i++) {
num += dupl * bittab[i];
dupl *= 2;
}
char decstring[30];
sprintf(decstring, "%ld\n", num);
for (i = 0; i < strlen(decstring); i++)
printf("%d\n", decstring[i] - '0');
The output is:
3
2
7
6
7
-38
This can be written into a dectab[] array, excluding the null terminator byte.
(I made the bits ascending to leave the size open.)

Luhn Algorithm in C

I'm very new to coding and one of the assignment is to program Luhn's Algorithm. After searching on the internet, everyone's solution looks so different and foreign :( so I don't know where the problem is with my solution. Any help is appreciated!
int main(void)
{
// get card number from user
long number;
do
{
number = get_long("Number: ");
} while (number < 0);
// isolate digits of card number
int digit;
int product;
int sum;
int totalSum;
int counter;
for (counter = 1; number > 9; counter++) {
for (int i = 1; number > 9; i = i * -1) {
digit = number % 10;
// isolate digits that need to be multiplied by 2
if (i == 1) {
product = digit * 2;
// add products' digits
if (product > 9) {
sum = (product % 10) + 1;
}
}
// add sum of digits that weren't multiplied by 2
totalSum = product + sum + digit;
// update "new" number
number = (number - digit) / 10;
}
}
// checksum
int check = totalSum % 10;
if (check != 0) {
printf("INVALID\n");
} else {
printf("VALID\n");
}
}
There are a number of errors in your code, most having to do with how you use variables.
You use totalSum without ever initializing it, which means it can start with any random value!
You add both product and sum to totalSum every time, but you only update their values when some condition applies.
This means at least half the time (maybe more) you add old values you already added previously.
Your loops exit when number is 9 or less, meaning you never check the leftmost (highest) digit of number.
As the comments suggested, you should read the pseudo code in Wikipedia, look carefully what they put in each variable, and what they sum and multiply.

Is there any way to reduce time complexity of the function given below?

This is the function to calculate the factorial of very large numbers. This works perfectly fine but the time complexity is quite high. How to reduce time complexity?
This function is called once.
Current time to find factorial 0f 1 million is 40 000ms;
Expected time: 10 000ms
static void calcfactorial(unsigned int n)
{
unsigned int carry, i, j;
len = factorial[0] = 1;
for (i = 1; i < LEN; i++)
factorial[i] = 0;
for (i = 2; i <= n; i++)
{
carry = 0;
for (j = 0; j < len; j++)
{
factorial[j] = factorial[j] * i + carry;
carry = factorial[j] / 10;
factorial[j] = factorial[j] % 10;
}
while (carry)
{
factorial[len++] = carry % 10;
carry = carry / 10;
}
}
}
Since you only need a four-fold improvement in time, the following may suffice:
Use a wider (unsigned) integer type, such as uint64_t.
Instead of calculating in base ten, use the largest power of ten, B, such that B•N fits in the integer type1, where N is the number you are computing the factorial of. For example, for 64-bit integers and 1,000,000!, you could use base 1013.
When doing multiplications, do not multiply by every digit in the product array, as the loop for (j = 0; j < len; j++) does. All digits beyond the first start as zero, and they slowly become non-zero as work progresses. Track the highest non-zero digit, and do multiplications only up to that digit, until the product carries into the next digit.
Similarly, the low digits become zero as the work progresses, due to accumulating factors of the base in the factorial. Track the lowest non-zero digit, and start work there.
A program demonstrating these is below.
A significant cost in this program is the divisions by the base. If you switch to a power-of-two base, these become bitwise operations (shifts for division and bitwise AND operations for remainders), which are much cheaper. This should speed up computing the factorial considerably. However, the final product will have to be converted to decimal for output. That will have a lower cost than computing entirely in decimal, so it is a win.
After that, you might consider this answer in Computer Science Stack Exchange. It suggests restructuring the factorial as powers of primes and using repeated squaring to compute the powers of primes, which are then multiplied.
This answer suggests using n! ≈ sqrt(2πn)•(n/e)n, which would require more sophisticated mathematics and programming.
Footnote
1 The purpose of using a power of ten is then the result can be directly printed from its base-B digits.
Demonstration
#include <inttypes.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
/* Define T to be an unsigned integer type. The larger the better up to the
widest type supported efficiently (generally the widest type for which the
processor has arithmetic instructions).
Define PRIuT to be a printf conversion specifier to print a type T as an
unsigned decimal numeral.
*/
typedef uint64_t T;
#define PRIuT PRIu64
// Return the base-10 logarithm of x, rounded down.
static unsigned ilog10(T x)
{
unsigned log = 0;
for (; 10 <= x; x /= 10)
++log;
return log;
}
// Return 10**x.
static T iexp10(unsigned x)
{
T power = 1;
for (; 0 < x; --x)
power *= 10;
return power;
}
int main(void)
{
// Set the value we want the factorial of.
static const T N = 1000000;
// Set the maximum value of T by using wrapping.
static const T MaximumT = -1;
/* Determine the maximum number of decimal digits we can use easily:
Given a number with Digits decimal digits, Digits*N will be
representable in a T.
*/
unsigned Digits = ilog10(MaximumT/N);
/* Set Base to 10**Digits. This is the numerical base we will do
arithmetic in -- like base ten, but more efficient if it is bigger.
*/
T Base = iexp10(Digits);
/* Set an array size that is sufficient to contain N!
For 1 < N, N! < N**N, so the number of digits in N! is less than
log10(N**N) = N * log(10). Since we are using ilog10, which rounds
down, we add 1 to it to round up, ensuring we have enough room.
Then we divide that number of digits by the number of digits we will
have in each array element (and round up, by subtracting one before the
division and adding one after), and that is the number of array
elements we allocate.
*/
size_t S = (N * (ilog10(N)+1) - 1) / Digits + 1;
T *Product = malloc(S * sizeof *Product);
if (!Product)
{
fprintf(stderr,
"Error, unable to allocate %zu bytes.\n", S * sizeof *Product);
exit(EXIT_FAILURE);
}
/* Initialize the array to 1. L and H remember the index of the lowest
and highest non-zero array element, respectively. Since all the
elements before L or after H are zero, we do not need to use them in
the multiplication.
*/
Product[0] = 1;
size_t L = 0, H = 0;
// Multiply the product by the numbers from 2 to N.
for (T i = 2; i <= N; ++i)
{
// Start with no carry.
T carry = 0;
/* Multiply each significant base-Base digit by i, add the carry in,
and separate the carry out. We start separately with the lowest
non-zero element so we can track if it becomes zero.
*/
while (1)
{
T t = Product[L] * i + carry;
carry = t / Base;
if ((Product[L] = t % Base)) // Leave when digit is non-zero.
break;
++L; // If digit is zero, increase L.
}
for (size_t j = L+1; j <= H; ++j)
{
T t = Product[j] * i + carry;
carry = t / Base;
Product[j] = t % Base;
}
// If there is a final carry out, put it in a new significant digit.
if (0 != carry)
Product[++H] = carry;
}
/* Print the result. The first base-Base digit is printed with no
leading zeros. All subsequent base-Base digits are printed with
leading zeros as needed to ensure exactly Digit decimal digits are
printed.
*/
printf("%" PRIuT, Product[H]);
for (size_t j = H; 0 < j--;)
printf("%0*" PRIuT, Digits, Product[j]);
printf("\n");
free(Product);
}

How to generate random long int in C where every digit is non-zero? Moreover the random numbers are repeating

I am making a library management in C for practice. Now, in studentEntry I need to generate a long int studentID in which every digit is non-zero. So, I am using this function:
long int generateStudentID(){
srand(time(NULL));
long int n = 0;
do
{
n = rand() % 10;
}while(n == 0);
int i;
for(i = 1; i < 10; i++)
{
n *= 10;
n += rand() % 10;
}
if(n < 0)
n = n * (-1); //StudentID will be positive
return n;
}
output
Name : khushit
phone No. : 987546321
active : 1
login : 0
StudentID : 2038393052
Wanted to add another student?(y/n)
I wanted to remove all zeros from it. Moreover, when I run the program the first time the random number will be the same as above, and second time random number is same as past runs like e.g:-
program run 1
StudentID : 2038393052
StudentID : 3436731238
program run 2
StudentID : 2038393052
StudentID : 3436731238
What do I need to fix these problems?
You can either do as gchen suggested and run a small loop that continues until the result is not zero (just like you did for the first digit) or accept a small bias and use rand() % 9 + 1.
The problem with the similar sequences has its reason with the coarse resolution of time(). If you run the second call of the function to fast after the first you get the same seed. You might read this description as proposed by user3386109 in the comments.
A nine-digit student ID with no zeros in the number can be generated by:
long generateStudentID(void)
{
long n = 0;
for (int i = 0; i < 9; i++)
n = n * 10 + (rand() % 9) + 1;
return n;
}
This generates a random digit between 1 and 9 by generating a digit between 0 and 8 with (rand() % 9) and adding 1. There's no need to for loops to avoid zeros.
Note that this does not call srand() — you should only call srand() once in a given program (under normal circumstances). Since a long must be at least 32 bits and a 9-digit number only requires 30 bits, there cannot be overflow to worry about.
It's possible to argue that the result is slightly biassed in favour of smaller digits. You could use a function call to eliminate that bias:
int unbiassed_random_int(int max)
{
int limit = RAND_MAX - RAND_MAX % max;
int value;
while ((value = rand()) >= limit)
;
return value % max;
}
If RAND_MAX is 32767 and max is 9, RAND_MAX % 9 is 7. If you don't ignore the values from 32760 upwards, you are more likely to get a digit in the range 0..7 than you are to get an 8 — there are 3642 ways to each of 0..7 and only 3641 ways to get 8. The difference is not large; it is smaller if RAND_MAX is bigger. For the purposes on hand, such refinement is not necessary.
Slightly modify the order of your original function should perform the trick. Instead of removing 0s, just do not add 0s.
long int generateStudentID(){
srand(time(NULL));
long int n = 0;
for(int i = 0; i < 10; i++)
{
long int m = 0;
do
{
m = rand() % 10;
}while(m == 0);
n *= 10;
n += m;
}
//Not needed as n won't be negative
//if(n < 0)
//n = n * (-1); //StudentID will be positive
return n;
}

C: print a BigInteger in base 10

I am using this struct to represent 128bit integers:
typedef struct {
uint64_t low, high;
} uint128;
(Unless you can point me to a fast 128bit integer library I can not change that)
Now I want to print such a value in base 10, using printf. I probably need division by 10 to do that, but no division is implemented yet.
How can I do this? The solution does not have to be super efficient, as long as it works.
EDIT: I like all solutions you came up with. You are awesome.
void printu128(uint128 n) {
int d[39] = {0}, i, j;
for (i = 63; i > -1; i--) {
if ((n.high >> i) & 1) d[0]++;
for (j = 0; j < 39; j++) d[j] *= 2;
for (j = 0; j < 38; j++) d[j+1] += d[j]/10, d[j] %= 10;
}
for (i = 63; i > -1; i--) {
if ((n.low >> i) & 1) d[0]++;
if (i > 0) for (j = 0; j < 39; j++) d[j] *= 2;
for (j = 0; j < 38; j++) d[j+1] += d[j]/10, d[j] %= 10;
}
for (i = 38; i > 0; i--) if (d[i] > 0) break;
for (; i > -1; i--) putchar('0'+d[i]);
}
If you don't want to implement division for 128bit value, you could precompute several (~40) 128 bit values that represents powers of 10, and use substraction.
Actually only higher qword have be processed in this way, because for lower part you can use printf("%I64d").
EDIT: here is an example (it will print a short using only arithmetics on char):
unsigned char pow10[][2] = {
{0, 1}, // 1
{0, 10}, // 10
{0, 100}, // 100
{3, 0xE8}, // 1k
{0x27, 0x10}}; // 10k == 0x2710
#define HIGH 0
#define LOW 1
void print_dec(unsigned char H, unsigned char L){
unsigned char L1;
int pwr = 4, ctr = 0;
while (pwr >= 0){
int c = pow10[pwr][LOW] > L;
L1 = L - pow10[pwr][LOW];
if (H >= pow10[pwr][HIGH] + c){
H -= pow10[pwr][HIGH] + c;
L = L1;
ctr++;
} else {
printf("%d", ctr);
ctr = 0;
pwr--;
//here we could add a check for H to be 0, so that we could use
//printf() for lower half. we just have to be careful with
//leading zeroes in L, the simpliest way is to use printf("%03d",L)
};
};
printf("\n");
};
int main(){
unsigned short n = 12345;
printf("%d should be ", n);
print_dec((n >> 8) & 0xFF, n & 0xFF);
return 0;
};
You can use smaller number of precomputed powers of 10, but it will make it slower (ex, having them in steps of 100 will make ctr to be in range 0..99.
Assuming you've already implemented functions to perform math on uint128, you could break the number up into 3 parts and use the built-in 64-bit printing capabilities of printf. Since the largest 64-bit number is 20 digits long, that means all 19-digit decimal numbers can be printed that way, but since the largest 128-bit number is 39 digits long, we can't break it up into only 2 parts, since there's a chance that we might end up with a 20 digit number bigger than the largest 64-bit number.
Here's one way to do it, dividing first by 1020 to get a quotient no larger than 3,402,823,669,209,384,634. We then divide the remainder (itself no larger than 1020) by 1010 to get another quotient and remainder each less than 1020, which both fit in a 64-bit integer.
void print_uint128(uint128 value)
{
// First power of 10 larger than 2^64
static const uint128 tenToThe20 = {7766279631452241920ull, 5ull};
static const uint128 tenToThe10 = {10000000000ull, 0ull};
// Do a 128-bit division; assume we have functions to divide, multiply, and
// subtract 128-bit numbers
uint128 quotient1 = div128(value, tenToThe20);
uint128 remainder1 = sub128(value, mul128(quotient, tenToThe20));
uint128 quotient2 = div128(remainder1, tenToThe10);
uint128 remainder2 = sub128(remainder1, mul128(remainder1, tenToThe10));
// Now print out theresult in 3 parts, being careful not to print
// unnecessary leading 0's
if(quotient1.low != 0)
printf("%llu%010llu%010llu", quotient1.low, quotient2.low, remainder2.low);
else if(quotient2.low != 0)
printf("%llu%010llu", quotient2.low, remainder2.low);
else
printf("%llu", remainder2.low);
}
You may use multiplication to print a number.
As 2128 is about 340E36, first determine leading digit, by comparing number with 100E36, 200E36 and 300E36 boundaries. Write a digit and subtract nearest lesser boundary. E. g. If number is 234.6776E36 then nearest lesser bounary is 200E36, digit is '2' and after subtraction you should get 34.6776E36.
Now get next digit using comparison with numbers 10E36...90E36. Of course it is 128 bit comparison. Write a digit and subtract hearest lesser boundary as above. (For 34.6776E36 from above digit is '3', boundary is 30E36 and remainder is 4.6776E36)
Then multiply number by 10 and repeat from stage 2, total 38 times to print each digit. (4.6776E36 -> 46.776E36...)
UPD: Added subtraction I missed first. And examples.
UPD2: The need of dedicated step for 1-st digit is jus because if you multiply the number next to it you should get an overflow, if remainder is greater than 34E36.

Resources