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.)
Related
I'm trying to create a program that breaks down a number into its component digits.
The code I've written so far is as follows:
#include <stdio.h>
int main() {
int num;
int digits;
int count = 1;
printf("Insert a positive number: ");
do {
scanf("%d", &num);
} while (num <= 0);
printf("In digits... \n");
// Number in digits
while (num != 0) {
digits = num % 10;
printf("Digit %d --> %d \n", count, digits);
num /= 10;
count++;
}
}
The digits of the number are printed correctly, but in reverse order!
Insert a positive number: 345
In digits...
Digit 1 --> 5
Digit 2 --> 4
Digit 3 --> 3
I can't figure out how to fix this, can anyone help me?
You're printing the number mod 10, which is the last digit, then dividing the number by 10 and repeating until the number is zero. So it prints the digits from right to left.
If you want to print from left to right, you need to print the digit that has the highest power of ten first. Here's a naive way to do that, by first finding the highest power of ten the number has a digit for and then using a for loop to go from that power to one to print the digits from left to right:
void print_digits(int n) {
int mask = 1;
for(int n2 = n; n2; n2 /= 10) mask *= 10; // find the left-most power of ten
for(int i = 1; mask > 1; mask /= 10) // loop over the mask to 1
printf("Digit %d --> %d\n", i++, (n % mask) * 10 / mask);
// print the digit number and increment the digit counter
// extract and print the digit:
// `n % mask` gets rid of everything to the left
// `* 10 / mask` gets rid of everything to the right
}
You could also make a simpler solution using the standard library function sprintf (string print formatted) to put the int into a string and then print from that, like so:
void print_digits(int n) {
char num[11]; // 32-bit int up to 9 digits, possible '-', and \0 -> 11
sprintf(num, "%d", n);
for (int i = 0; num[i]; i++)
printf("Digit %d --> %c\n", i + 1, num[i]);
}
The second might also be a tiny bit more performant due to not involving division, but I'm not certain of that and such minor differences don't matter for a problem like this anyway
Your code prints them in reverse because you are starting with the right-most digit (by taking the modulo by 10) each time, then dividing by 10.
To print from left to right, you could have:
#include <stdint.h>
void print_uint32_digits(uint32_t val)
{
int started = 0; // Flag to say we have started printing digits
// Special case for when val is zero
if (val == 0u)
{
printf("0\n");
return;
}
for (uint32_t divider = 1000000000u; divider != 0u; divider /= 10u)
{
uint32_t num = val / divider;
if (num > 0u || started)
{
printf("%c", num + '0');
started = 1;
val -= (num * divider);
}
}
printf("\n");
}
Some notes - I've used uint32_t because it is unsigned and a nice length. To make it work with plain "ints" would involve handling the case of negative numbers, which is more complex. I don't know if you need to handle negative numbers. (Also, ints on your platform could be 64-bit, so the initial divider would have to be adjusted accordingly.)
The 'started' flag is used to signal when we have output at least one digit, to ensure zeros get printed correctly. Until that flag is set, leading zeros are not printed.
A very simple recursive solution looks like this:
void print_num(int num)
{
if (num < 10)
fputc('0' + num, stdout);
else {
print_num(num/10);
print_num(num%10);
}
}
Can any one help me sort out one problem, i have to reverse a number without using array(int/char) for storing them.
input1 = 123
output1 = 321
input2 = 2300
output2 = 0032
I am trying to find the solution but 0 got erased while printing so i thought of octal conversion but still no solution, so i went with the decimal places and i made the 23 to 0.0032. Now my problem is how can i extract the 0032 from that part.
Is there any possible way to achieve this without using array(int/char), with that it will be easy.
#include<stdio.h>
#include<math.h>
int main()
{
int number =3200;
int temp;
while (number >0)
{
temp= number%10;
printf("%d",temp);
number = number/10;
}
return 0;
}
you could use recursion to solve this problem, without using any array in fact u could also reverse a string without using any array using recursion. This code works for both numbers and strings and it has no arrays:
char reverse(int a)
{
char c,d;
if(a=='\n')
return 0;
c=getchar();
d=reverse(c);
putchar(a);
return (c);
}
int main()
{
char c;
scanf("%c",&c);
reverse(c);
}
for a start try this.
int n, l;
char nBuf[126];
n = 1230010;
l = sprintf(nBuf, "%d", n );
while( l >= 0 )
printf("%c", nBuf[l--] );
Though if you are taking input from stdin take it as string rathar than as int or long.
Edit - for not using array
int n = 123;
while(n) {
printf("%d", n%10);
n/=10;
}
I am assuming to get a value of this sort "output2 = 0032" it is better of being a string, else formatting complications turns up with input value length and format left space with zeros etc etc.
This becomes fairly easy if you know that you can represent numbers like so:
x = a_0 + a_1 * b^1 + a_2 * b^2 + ...
a_i are the digits
b is the base
To extract the lowest digit, you can use the remainder: x % b
Dividing by the base "removes" the last digit. That way you can get the digits in order lowest to highest.
If you reverse the digits then the lowest becomes the highest. Looking at below transformation it's easy to see how to incrementally build up a number when the digits come in order highest to lowest:
x = a_0 + b * (a_1 + b * (a_2 + ...
You start of with 0, and for each digit you multiply with the base and then add the digit.
In pseudo code:
output = 0
while input != 0
digit = input % base
input = input / base ;; integer division
output = output * base + digit
end
If you want to store leading zeros, then you need to either store the digits in an array, or remember for how many steps of above loop the output remained zero:
output = 0
zeros = 0
while input != 0
digit = input % base
input = input / base ;; integer division
output = output * base + digit
if output == 0
zeros = zeros + 1
end
end
To print that you obviously need to print zeros zeros and then the number.
Live example here, relevant code:
unsigned reverse(
unsigned input,
unsigned const base,
unsigned * const zeros) {
unsigned output = 0;
unsigned still_zero = 0;
for (; input != 0; input/=base) {
output *= base;
output += input % base;
if (output == 0) {
++still_zero;
}
}
if (zeros != NULL) {
*zeros = still_zero;
}
return output;
}
void print_zeros(unsigned zeros) {
for (; zeros != 0; --zeros) {
printf("0");
}
}
Recursion allows for a simple solution. A small variation on #vishu rathore
void rev_dec(void) {
int ch = getchar();
if (isdigit(ch)) {
rev_dec();
}
if (ch >= 0) putchar(ch);
}
int main(void) {
rev_dec();
return 0;
}
input
0123456789012345678901234567890123456789
output
9876543210987654321098765432109876543210
When I run this code, I get outputs that don't really make any sense. I'm most likely just missing something, but I've been working on trying to find the problem with my code by working out the problems by hand, but I'm getting the values I should be getting when I do it by hand. A simplified version of this calculation is (c%10^n - c%10^(n-1)) / 10^(n-1).
The goal of this calculation is to assign the digits of a number to an array of ints. I'm not really looking for alternate solutions.
int cNumberV[nLength];
for(int n = nLength; n > 0; n--) {
cNumberV[nLength - n] = (cNumber % (long long) pow(10, n) - cNumber % (long long) pow(10, n - 1)) / (long long) pow(10, n - 1);
printf("%i\n", cNumberV[n]);
}
This is my output when cNumber = 5105105105105100 and nLength = 16:
-1981492631
232830
-1530494976
1188624
-397102900
134514540
-1081801416
1188624
0
1
5
0
1
5
0
1
The problem is that your loop sets cNumberV[nLength - n], but then prints out cNumberV[n].
So the first half of the loop prints uninitialized array entries, and the second half of the loop prints the result of the first half's calculation in reverse order (but due to an off-by-one error as pointed out by rowan.G, it never prints the first digit).
pow() is an expensive and inaccurate floating function. You only
need simple integer divide by ten to get digits. If you really want
to get them left-to-right as you do above, make a lookup table with
the 19 powers of 10 as integers.
#include <stdio.h>
#define nLength 20
long long cNumber = 5105105105105100;
int cNumberV[nLength];
int negative = 0;
int main(int argc, char *argv[]) {
if (cNumber < 0) {
negative = 1;
cNumber = -cNumber;
}
int n;
for (n = nLength - 1; n >= 0; n -= 1) {
cNumberV[n] = cNumber % 10;
cNumber /= 10;
if (0 == cNumber) break;
}
if (negative) printf("-");
for (int i = n; i < nLength; i += 1) {
printf("%1d", cNumberV[i]);
}
printf("\n");
}
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.
I am working with a PIC microprocessor, in C. It's a 16F, so it can't hold integers larger than 32bits (unsigned int32 is the largest datasize available)
From a reader, I receive a 5 byte ID code. To transmit it, I have to encoded to BCD, digit by digit. I can't sprint it to a string, as it is larger that the data size, and can't process it. I can't divide it because no operation is defined for it.
I can't figure out any solution possible, does anyone have dealt with this before?
EDIT:
I receive the number in a series of 5 bytes:
FF-FF-FF-FF-FF
I need to convert it to decimal
0123456789012
(13 digits, length of 256^5 in decimal) to send it through RS232. The second function (Take the ASCII, and send it) I already have it working, but I need the string representation of the full number before I can do anything with it.
Assuming you have 32 bit arithmetic: 2**24 = 16777216, so taking x as the most significant 2 bytes and y as the least significant 3:
(16777216 * x + y) / 1000
= (16777000 * x + 216 * x + y) / 1000
= 16777 * x + (216 * x + y) / 1000
The first term can be calculated in 32 bits without overflow (since x < 2**16).
The second term can also be calculated without overflow (since x < 2**16 and y < 2**24).
This is basically long division in base 2**24 of a 2-digit value, but with terms pre-calculated knowing that the divisor is 1000. One thousand is chosen because it's the least power of 10 greater than 2**8.
So, first compute the lowest three digits, use the fact that (2**32) % 1000 == 296. So this time we'll take x as the highest byte and y as the low 4 bytes
((2**32) * x + y) % 1000 = ((2**32) * x) % 1000 + y % 1000 (modulo 1000)
= (296 * x) % 1000 + y % 1000 (modulo 1000)
((2**32) * x + y) % 1000 = ((296 * x) % 1000 + y % 1000) % 1000
Then divide the original number by 1000 using the formula above. Then you're safely into 32 bit territory and can churn out the remaining digits using the normal loop.
Btw, I'd check the results if I were you: I haven't tested this and it's possible I've made an error somewhere. It should be easy to compare against the results of bcd conversions done using the usual means in a 64-bit integer on a PC.
What I would do, is implement addition and multiplication for numbers coded as a string (sort of BigNum). That way, you can sprintf the most significant byte of your ID to a string "A", multiply it with the string "4294967296" (256^4) giving you string "B", sprintf the 4 least significant bytes of your ID in another string "C", and finally adding "B" and "C".
It's not very sexy, especially on a micro-controller, but it works :)
The PIC16F does not have a hardware multiply or divide unit, so unless you are multiplying or dividing by a power of 2, it is taxing to the processor. Here is a routine that does a BCD on a 32 bit number and doesn't require division or multiplication. You could adapt this to a 5 byte number by doing it in chunks.
void BCD32(int32u numIn)
{
int8u digit = 0;
while (numIn >= 1000000000)
{
numIn -= 1000000000;
digit++;
}
debug[0] = digit + 48;
digit = 0;
while (numIn >= 100000000)
{
numIn -= 100000000;
digit++;
}
debug[1] = digit + 48;
digit = 0;
while (numIn >= 10000000)
{
numIn -= 10000000;
digit++;
}
debug[2] = digit + 48;
digit = 0;
while (numIn >= 1000000)
{
numIn -= 1000000;
digit++;
}
debug[3] = digit + 48;
digit = 0;
while (numIn >= 100000)
{
numIn -= 100000;
digit++;
}
debug[4] = digit + 48;
digit = 0;
while (numIn >= 10000)
{
numIn -= 10000;
digit++;
}
debug[5] = digit + 48;
digit = 0;
while (numIn >= 1000)
{
numIn -= 1000;
digit++;
}
debug[6] = digit + 48;
digit = 0;
while (numIn >= 100)
{
numIn -= 100;
digit++;
}
debug[7] = digit + 48;
digit = 0;
while (numIn >= 10)
{
numIn -= 10;
digit++;
}
debug[8] = digit + 48;
digit = 0;
while (numIn >= 1)
{
numIn -= 1;
digit++;
}
debug[9] = digit + 48;
debug[10] = CARRIAGE_RETURN;
debug[11] = NEW_LINE_FEED;
SendUart(12);
}
You can always "sprintf" it to a string manually yourself. go over the data byte after byte and convert it to a numerical string by appending individual characters.
The core of this problem I would say is one of "long division" to convert to decimal. Not entirely unlike long division you learned in grade school, though with binary numbers, long division is much simpler. But its still a lot of work.
try:
http://mathforum.org/library/drmath/view/55951.html
You will have to implement your own multi-byte subtraction and shift routines.