How to efficienty count from 0000 to 9999 in a digit display? - c

I've n display that count from 0 to 9. I'd like to make an efficient code for a micro in C language. What I've wrote is:
dis_value[0]++;
if (dis_value[0] > 9) {
dis_value[0] = 0;
dis_value[1]++;
}
if (dis_value[1] > 9) {
dis_value[0] = 0;
dis_value[1] = 0;
dis_value[2]++;
}
if (dis_value[2] > 9) {
dis_value[0] = 0;
dis_value[1] = 0;
dis_value[2] = 0;
dis_value[3]++;
}
if (dis_value[3] > 9) {
dis_value[0] = 0;
dis_value[1] = 0;
dis_value[2] = 0;
dis_value[3] = 0;
}
Where from 0 to 3 are display module number.
Is that the best way?
Or maybe is better a single counter of 16bit that is split into 4 different part?

You can nest the digit reset or increment
dis_value[0]++;
if (dis_value[0] > 9) {
dis_value[0] = 0;
dis_value[1]++;
if (dis_value[1] > 9) {
dis_value[1] = 0;
dis_value[2]++;
if (dis_value[2] > 9) {
dis_value[2] = 0;
dis_value[3]++;
if (dis_value[3] > 9) {
dis_value[3] = 0;
}
}
}
}
By doing above you are not unnecessarily executing all the ifs.

char *inc(char *buff, unsigned *i)
{
unsigned tmp = ++(*i);
buff[0] = tmp % 10;
tmp /= 10;
buff[1] = tmp % 10;
tmp /= 10;
buff[2] = tmp % 10;
tmp /= 10;
buff[3] = tmp % 10;
return buff;
}

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
void delay(int number_of_seconds)
{
int milli_seconds = 1000 * number_of_seconds;
clock_t start_time = clock();
while (clock() < start_time + milli_seconds);
}
int main(int argc, const char *argv[])
{
int arr[4] = {0};
for(int i=0; i < 4; i++)
{
for(int j = 0; j<9; j++)
{
arr[i]++;
delay(1000);
printf("%i%i%i%i\n",arr[3], arr[2], arr[1], arr[0]);
}
}
printf("\n");
return 0;
}

I spotted you want to keep the code with minimal dependencise on a microcontroller.
If you are willing to treat the dis_value buffer as an integer, with one byte per digit, say little-endian, which can be held in a register, which should also be faster, then you can combine the sequence:
if (dis_value[N] > 9) {
dis_value[N] = 0;
dis_value[N+1]++;
It becomes (with #kiran 's nesting)
if ((dis_value&(0xf<<(N*8)))==(10<<(N*8)))
{
dis_value+=(0x100-10)<<(N*8);
if ...
}
Where I am presuming the compiler will resolve the constant expressions.
It would also be good to reverse the addition and the if in order to improve conditional pipeline evaluation, if your controller has a pipeline, but that means writing assembler code.
The following pseudocode should give the idea. The next condition is evaluated using the value before the addition, so the two operations can be performed in parallel. If you were actually encoding this to a circuit, this is an obvious optimisation:
bool do0 = ((dis_value&(0xf<<(0*8)))==(9<<(0*8)))
dis_value++;
if (do0)
{
bool do1 = ((dis_value&(0xf<<(1*8)))==(9<<(1*8)));
dis_value += (0x100-10)<<(0*8);
if (do1)
{
do2 = ((dis_value&(0xf<<(2*8)))==(9<<(2*8)));
dis_value += (0x100-10)<<(1*8);
if (do2) ...
}
}
The next question to ask is how can you minimally update a segmented display for an increment!

simulate math addition would suffice, checking from the lowest digit to the highest.
#include <stdio.h>
void incr(int dis_value[], int n) {
++dis_value[0];
for (int i=0; i+1<n; ++i) {
if (dis_value[i] < 10) break;
dis_value[i+1] += dis_value[i] / 10;
dis_value[i] %= 10;
}
dis_value[n-1] %= 10;
}
void echo(int dis_value[], int n) {
for (int i=n-1; i>=0; --i) printf("%d", dis_value[i]);
printf("\n");
}
int main() {
int dis_value[] = {0, 0, 0, 0};
for (int i=0; i<10000; ++i) {
incr(dis_value, 4);
echo(dis_value, 4);
}
return 0;
}

Related

Why doesn't equating two sums in a conditional evaluate to true?

I am trying to return the index where the sum of the left hand side is equal to the right hand side. But I get a default of -1. Why doesn't the conditional evaluate to true?
Here is the code:
#include <stdio.h>
int find_even_index(const int *values, int length)
{
int count = 0;
int sumL = 0;
int sumR = 0;
while(count < length)
{
sumR += values[count];
count++;
}
count = 0;
while(count < length)
{
sumL += values[count];
sumR -= values[count];
printf("sumL = %d\n", sumL);
printf("sumR = %d\n", sumR);
if(sumL == sumR)//why doesn't this condition work?
{
return count;
}
count++;
}
return -1;
}
int main (void)
{
int arr[] = { 1,2,3,4,3,2,1 };
printf("%d\n", (find_even_index(arr, 7)));
return 0;
}
Because you are comparing the numbers after adding and subtracting both of them. So in the moment they are about to be the same:
sumL = 6; sumR = 10
You then sum 4 to sumL and subtract 4 to sumR:
sumL = 10; sumR = 6
And then you compare and get different values. You have to check in between the operations.

Adding two numbers [1, 10^10000] as arrays of chars - C

I tackled the problem by first figuring out the length of two given numbers and aligning the one with less digits (if one exists) into a new array so that the ones, tens, hundreds etc. align with the bigger number's ones, tens, hundreds, etc.
Then I wanted to save the sum of each two aligned elements (with a mod of 10) into a new array while checking if the sum of digits is greater than 10 - just the basic sum stuff. Now the problem occurs with adding two elements into the aplusb integer and I've tried fixing it with writing
int aplusb = (lengthA[max-i]-'0') +(temp[max-i]-'0');
but it doesn't work. I'm stuck and I don't know what to do. Please help.
The whole code:
#include <stdio.h>
#include <math.h>
int main(){
char a[10000];
char b[10000];
scanf("%s %s", &a, &b);
char sum[10000];
int lengthA = 0;
int lengthB = 0;
int i = 0;
while(a[i]){
i++;
} lengthA = i;
i = 0;
while(b[i]){
i++;
} lengthB = i;
char temp[10000];
int aplusb;
int carry = 0;
int max = lengthA;
int difference = abs(lengthA - lengthB);
if(lengthA>lengthB){
for(i=0; i<lengthA; i++){
temp[i+difference]=b[i];
}
for(i=0; i<=max; i++){
aplusb = lengthA[max-i]+temp[max-i]; //<-- this is the problematic line
if(carry = 1) aplusb++;
if(aplusb>9){
carry = 1;
aplusb%=10;
}
sum[i]=aplusb;
}
}
for(i=0; i<=max; i++){
printf("%c", sum[i]);
}
/*
if(lengthB>lengthA){
max = lengthB;
for(i=0; i<lengthB; i++){
temp[i+difference]=a[i];
}
}*/
return 0;
}
Doing operations and storing on very large numbers is very akin to doing operations and storing polynomials, i.e. with x = 10. a0 + a1.10 + a2.10^2 ... + an.10^n.
There are many polynomial libraries on the Internet, where you could find inspiration. All operations on your very large numbers can be expressed in terms of polynomials. This means that by using base 2^8, or even base 2^63, instead of base 10 to internally store your large numbers you would greatly improve performance.
You must also normalize your coefficients after operations to keep them positive. Operations may result in a negative coefficient, That can easily be fixed, as it is very similar to borrowing after a subtraction, this means coefficients must be larger than your base by 1bit.
To convert back to base 10, you'd need to solve r (your result) for v (your value), such as r(10)=v(2^63). This has only one solution, if you enforce the positive coefficients rule.
[note] After thinking about it some more: the rule on positive coefficients may only be necessary for printing, after all.
Example: adding. no memory error checking
int addPolys(signed char** result, int na, const signed char* a, int nb, const signed char* b)
{
int i, nr, nmin, carry, *r;
nr = max(na, nb) + 1;
nmin = min(na, nb);
r = malloc(sizeof(signed char) * (na + nb + 1));
if (nb < na)
{
nr = nb;
}
for (i = 0; i < nmin; ++i)
{
r[i] = a[i] + b[i];
}
for (; i < na; ++i)
{
r[i] = a[i];
}
for (; i < nb; ++i)
{
r[i] = b[i];
}
r[nr - 1] = 0;
// carry - should really be a proc of its own, unoptimized
carry = 0;
for (i = 0; i < nr; ++i)
{
r[i] += carry;
if (r[i] > 10)
{
carry = r[i] / 10;
r[i] %= 10;
}
else if (r[i] < 0)
{
carry = (r[i] / 10) - 1;
r[i] -= (carry * 10);
}
else
carry = 0;
}
// 'remove' leading zeroes
for (i = nr - 1; i > 0; --i)
{
if (r[i] != 0) break;
}
++i;
*result = r;
if (i != nr)
{
*result = realloc(i * sizeof(signed char));
}
return i; // return number of digits (0 being 1 digit long)
}
That code is working now for any two positive numbers with up to ten thousand digits:
#include <stdio.h>
#include <math.h>
#include <string.h>
int main(){
char chara[10000];
char charb[10000];
scanf("%s %s", &chara, &charb);
int lengthA = strlen(chara);
int lengthB = strlen(charb);
int max = lengthA;
if(lengthB>lengthA) max=lengthB;
int dif = abs(lengthA - lengthB);
//ustvari int tabele
int a[max];
int b[max];
int sum[max+1];
// nastavi nule
int i;
for(i=0; i<max; i++){
a[i] = 0;
b[i] = 0;
sum[i] = 0;
} sum[max] = 0;
//prekopiraj stevila iz char v int tabele &obrni vrstni red
for(i=0; i<lengthA; i++){
a[i] = chara[lengthA-i-1]-'0';
}
for(i=0; i<lengthB; i++){
b[i] = charb[lengthB-i-1]-'0';
}
int vsota;
int prenos = 0;
for(i=0; i<max; i++){
vsota = a[i]+b[i] + prenos;
if(vsota>=10) prenos = 1;
else if (vsota<10) prenos = 0;
sum[i]=vsota%10;
}
if(prenos==1){
sum[max] = 1;
for(i = max; i>=0; i--){
printf("%d", sum[i]);
}
} else {
for(i = max-1; i>=0; i--){
printf("%d", sum[i]);
}
}
return 0;
}

Access Violation in C program involving pointer variable?

I was trying to solve Project Euler question 16 using c. I did not use bignnum libraries. The question asks 2^1000. I decided to store every digit of that number in an array.
For Example: 45 means arr[0]=4, arr[1]=5;
The problem is definitely i the function int multi.
#include<stdio.h>
#include<conio.h>
int multi(int *base, int k);// does the multiplication of array term by 2
void switcher();//switches every term when the fore mostvalue is >10
int finder();// finds the array address of last value
int arr[1000];
int summer();//sums all values of the array
int main()
{
arr[1000] = { 0 };
arr[0] = 1;
int i, j, sum, k, p;
for (i = 0; i < 1000; i++)
{
j = 0;
k = finder();
p = multi(arr + k, j);
}
sum = summer();
printf("sum of digits of 2^1000 is %d", sum);
_getch();
}
int multi(int *base, int k)
{
int p;
if (base == arr)
{
*base = *base - 1;
*base = *base + k;
if (*base > 10)
{
*base = *base - 10;
switcher();
}
return 0;
}
*base = *base * 2;
*base = *base + k;
if (*base > 10)
{
*base = *base - 10;
p = multi(base - 1, 1);
}
else
{
p = multi(base - 1, 0);
}
}
void switcher()
{
int j;
for (j = 0;; j++)
{
if (arr[j] == 0)
{
break;
}
}
j--;
for (; j > 0; j--)
{
arr[j + 1] = arr[j];
}
arr[0] = 1;
}
int finder()
{
int j;
for (j = 0;; j++)
{
if (arr[j] == 0)
{
break;
}
}
return --j;
}
int summer()
{
int summ, i;
summ = 0;
for (i = 0; i<1000; i++)
{
summ = summ + arr[i];
if (arr[i] == 0)
break;
}
return summ;
}
It compiles but during runtime it shows Access Write Violation, base was ......
Please explain this error and how to resolve it ?
Array is of 100 Bytes but you are looping for 1000. Also in function Finder() , you do not have a limit on variable j so your array size is going beyond 100 bytes.
Also use memset to assign array variables to 0.
As said in the comments, 2^1000 has 302 decimal digits.
You're going far outside your array.
But your code is very complicated because you store the digits with the most significant one first.
Since you're only interested in the digits and not the order in which they would be written, you can store the number "in reverse", with the least significant digit first.
This makes the code much simpler, as you can loop "forwards" and no longer need to shuffle array elements around.
Using -1 as "end of number" marker, it might look like this:
void twice(int* digits)
{
int i = 0;
int carry = 0;
while (digits[i] >= 0)
{
digits[i] *= 2;
digits[i] += carry;
if (digits[i] >= 10)
{
carry = 1;
digits[i] -= 10;
}
else
{
carry = 0;
}
i++;
}
if (carry)
{
digits[i] = 1;
digits[i+1] = -1;
}
}
int main()
{
int digits[302] = {1, -1}; /* Start with 1 */
twice(digits); /* digits is now { 2, -1 } */
return 0;
}

In C, I would like to print 4 decimal numbers in a row and then print the next 4

#include "stdio.h"
int main() {
int max = 1000;
for (int i = 0; i < max; ++i) {
printf("%d", i);
}
return 0;
}
If max is 1000 then this will print in the format shown below
0123 up to 1000
But I would like to print 4 values per line as shown below:
0123
4567
...
I would like to see the numbers not the just the digits. for a single digit numbers, it should be like this: 0123 for two digit numbers, it should be like this: 11121314 for a three digit numbers, it should be like this: 111112113114 up to 996997998999 up to 1000.
For your loop to print upto and including 1000 for max.size = 1000, you must use the <= operator.
Here is a modified version that will format the output with a maximum of 4 characters per line:
#include <stdio.h>
#include <limits.h>
int main(void) {
struct { int size; } max = { 1000 };
if (max.size >= 0) {
for (int col = 0, i = 0;; i++) {
char buf[2 + sizeof(int) * CHAR_BIT / 3];
int n = snprintf(buf, sizeof buf, "%d", i);
for (int j = 0; j < n; j++) {
putchar(buf[j]);
if (++col == 4) {
putchar('\n');
col = 0;
}
}
if (i == max.size) {
if (col > 0) {
putchar('\n');
}
break;
}
}
}
return 0;
}
It will print:
0123
4567
8910
1112
1718
...
6997
9989
9910
00
EDIT
From your updated question, it is actually much simpler: print a linefeed character after every 4th number, using the modulo operator %.
#include <stdio.h>
int main(void) {
int max = 1000;
for (int i = 0; i < max; ++i) {
printf("%d", i);
if (i % 4 == 3)
putchar('\n');
}
return 0;
}
Just check whether i+1 is divisible by 4 or not. Whenever it is divisible by 4, print a newline.
for (int i = 0; i < max.size; ++i) {
printf("%d", i);
if((i+1)%4 == 0)
printf("\n");
}
You can also do this without using a buffer:
#include <stdio.h>
void print_digit(int number);
int main(void) {
putchar('0');
int i;
for(i = 1; i <= 1000; i++) {
print_digit(i);
}
}
void print_digit(int number) {
static int digit_count = 1; // a zero is already printed
int i;
for(i = 1; i <= number; i *= 10);
for(i /= 10; i; i /= 10) {
putchar('0' + number % (i * 10) / i);
digit_count++;
if(digit_count == 4) {
digit_count = 0;
putchar('\n');
}
}
}
However, I have to admit that this code has nothing to do with elegance, because I don't know how to make print_digit consistent with zero.

How many times a digit is appeared in a number

Well, I wrote the code and everything is fine except one thing.
When I enter that digit number, which has to be upto 10 digits, I recieve in arr[0] various values, for example, if I enter "12345" I get 20, 1 , 1 , 1 , 1 , 1 , 0 ,0 ,0 ,0.
Which is fine from arr[1] to arr[9], but pretty odd in arr[0].
Any ideas?
#include <stdio.h>
#include <conio.h>
#include <math.h>
void main()
{
int i,j,p=0, temp,indexNum, arr[10] = { 0 }, num, level = 10, level2 = 1,maxIndex;
printf("Please enter a digit number (upto 10 digits) \n");
scanf("%d", &num);
temp = num;
while (temp > 0)
{
p++;
temp /= 10;
}
for (i = 0;i < p;i++)
{
temp = num;
while (temp > 0)
{
indexNum = num % level / level2;
arr[indexNum]++;
level *= 10;
level2 *= 10;
temp /= 10;
}
}
for (j = 0; j < 10; j++)
{
printf("%d\n", arr[j]);
}
getch();
}
Here is simplified version of your program:
#include <stdio.h>
#include <math.h>
int main()
{
int i = 0, j = 0, temp = 0, indexNum = 0, num = 0, level = 10;
int arr[10] = {0};
num = 7766123;
temp = num;
if(0 == temp) arr[0] = 1; // Handle 0 input this way
while (temp > 0)
{
indexNum = temp % level;
arr[indexNum]++;
temp /= 10;
}
for (j = 0; j < 10; j++)
{
printf("%d\n", arr[j]);
}
return 0;
}
A few hints to help you:
What does arr[10] = { 0 } actually do?
When you calculate indexNum, you are dividing integers. What happens when the modulus is a one-digit number, and level2 is greater than 1?
It's probably easier to read the input into a string and count digit characters. Something like this (not tested):
std::map<char, int> count;
std::string input;
std::cin >> input;
for (auto iter = input.begin(); iter != input.end(); ++iter) {
if (*iter < 0 || *iter > 9)
break;
else
++count[*iter];
}
for (auto iter = count.begin(); iter != count.end(); ++iter) {
std::cout << *iter << '\n';
}
You need to get rid of your first for loop. Something more like:
#include <stdio.h>
#include <math.h>
using namespace std;
int main()
{
int j;
int temp;
int indexNum;
int arr[10] = { 0 };
int num;
int level = 10;
int level2 = 1;
printf("Please enter a digit number (upto 10 digits) \n");
scanf("%d", &num);
temp = num;
while (temp > 0)
{
indexNum = num % level / level2;
arr[indexNum]++;
level *= 10;
level2 *= 10;
temp /= 10;
}
for (j = 0; j < 10; j++)
{
printf("%d\n", arr[j]);
}
return 0;
}
Check the program below.
void count_digits(unsigned int a, int count[])
{
unsigned int last_digit = 0;
if (a == 0) {
count[0] = 1;
}
while (a != 0)
{
last_digit = a%10;
count[last_digit]++;
a = a/10;
}
}
int main()
{
int count[10]= {0};
unsigned int num = 1122345; /* This is the input, Change it as per your need */
int i = 0;
count_digits(num, count);
for (i = 0; i < 10; i++)
{
printf ("%d: -- %d\n", i, count[i]);
}
return 0;
}

Resources