Related
I'm searching for a fast permutation of bits within a number in C.
I have an integer value and table of permutation positions. Not all possible permutations are listet, just n!*2n of the 2n! possible permutations.
For simplicity I will show the data as 4-Bit numbers (n=2, lutsize = 8), in reality they are 32-Bit numbers (n=5, lutsize=3840):
static const uint8_t lut[lutsize][4] = {
{0, 1, 2, 3},
{1, 0, 3, 2},
{2, 3, 0, 1},
{3, 2, 1, 0},
{0, 2, 1, 3},
{1, 3, 0, 2},
{2, 0, 3, 1},
{3, 1, 2, 0}};
So the first entry is the identity, for the second entry the bits 1&2 and 2&3 switch places and so on. I wrote a method which calculates the values and returns the minimal value:
#include <stdio.h>
#include <stdint.h>
#include <assert.h>
enum { n = 2 };
enum { expn = 1<<n };
enum { lutsize = 8 };
static const uint8_t lut[lutsize][4] = {
{0, 1, 2, 3},
{1, 0, 3, 2},
{2, 3, 0, 1},
{3, 2, 1, 0},
{0, 2, 1, 3},
{1, 3, 0, 2},
{2, 0, 3, 1},
{3, 1, 2, 0}
};
uint32_t getMin(uint32_t in, uint32_t* ptr){
uint32_t pos, i, tmp, min;
uint8_t bits[expn];
tmp = in;
for (i = 0; i < expn; ++i){ // extract bits into array
bits[i] = tmp & 1;
tmp = tmp >> 1;
}
min = in;
for (pos = 0; pos < lutsize; ++pos){ // for each row in the permutation table
tmp = 0;
for (i = 0; i < expn; ++i){ // for each bit
tmp = tmp | (bits[i] << lut[pos][i]); // put bit i on position lut[pos][i]
}
ptr[pos] = tmp; // store result (optional)
//printf("%d: %d\n", pos, tmp);
if (tmp<min) { min = tmp; } // track minimum
}
//printf("min: %d\n", min);
return min;
}
void main(int argc, const char * argv[]) {
uint32_t ptr[lutsize];
printf("%u\n", (unsigned)getMin(5, ptr));
assert(getMin(5, ptr) == 3);
assert(getMin(0b0110, ptr) == 6);
}
gives the output for the example number 5 if you uncomment the printf's:
0: 5
1: 10
2: 5
3: 10
4: 3
5: 3
6: 12
7: 12
min: 3
I do calculate each permutation in a naive way by separating the bits into an array and then pushing them into their new position. I write the results into an array and keep track of the minimum which is returned at the end.
How do improve the performance of the procedure getMin for n=5?
I'm primarily interested in the minimum.
Additional input:
the permutation table can be read as "bit value comes from position" or "bit value shifts to position". The results are the same, just the order of the entries differs.
it is not necessary (but a bonus) to use the array (ptr)
the goal is to reduce the time to compute the smallest bit permutation number for all 32-bit numbers in random order. Precalculating all possible minimum numbers is ok. Using multiple versions of the lut is ok. Anything is ok as long it does not take more than 4GB of ram like storing all possible input/output pairs would do.
sorry for the not so c-like code. I'm out of training.
Here is the python code to generate the look up table for n=5:
from itertools import permutations
import numpy as np
import math
for n in [5]:
expn = 1<<n #2:4 3:8; 4:16; 5:32
order = np.zeros((int(math.factorial(n))*expn, expn), dtype=np.int8) # n!*2^n x 2^n matrix
cnt = 0 # current entry
permneg = np.zeros(expn, dtype=int)
for perm in permutations(list(range(n))): #shuffle order
ini = np.array(list(range(expn)), dtype=int) # list 0 to expn-1
out = np.zeros(expn, dtype=int)
for i in range(n): # apply permutation on position level
tmp = ini & 1 # get value on least bit
out += tmp << perm[i] #put it on the right postion
ini = ini >> 1 # next bit as least bit
for neg in range(expn): # include 0/1 swaps (negation)
for i in range(len(out)): # for all 2^n negation cases
permneg[i] = out[i] ^ neg # negate on negation bits
order[cnt]=permneg # store
cnt += 1 # increase counter
print("enum { lutsize = "+str(len(order))+" };")
s='},\n{'.join(', '.join(map(str,sl)) for sl in order)
print("static const uint8_t lut[lutsize]["+str(expn)+"] = {\n{"+s+"}\n};")
I would suggest two optimizations : 1) store the value of the set bit in the table instead. 2) Don't store each bit in an array but compute it on the fly instead. The result is the same, but it's probably a little bit faster.
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#define lutsize 8
static const uint8_t lutn[lutsize][4] = {
{1, 2, 4, 8},
{2, 1, 8, 4},
{4, 8, 1, 2},
{8, 4, 2, 1},
{1, 4, 2, 8},
{2, 8, 1, 4},
{4, 1, 8, 2},
{8, 2, 4, 1}};
uint32_t getMin(uint32_t in, uint32_t* ptr)
{
uint32_t pos, i, tmp, min;
uint8_t bits[expn];
tmp = in;
min = in;
for (pos = 0; pos < lutsize; ++pos){
tmp = 0;
for (i = 0; i < expn; ++i) {
// If the bit is set
if (in & (1<<i))
// get the value of the permuted bit in the table
tmp = tmp | lutn[pos][i];
}
ptr[pos] = tmp;
//printf("%d: %d\n", pos, tmp);
if (tmp<min) { min = tmp; } // track minimum
}
//printf("min: %d\n", min);
return min;
}
void main(int argc, const char * argv[]) {
uint32_t *ptr;
ptr = (uint32_t*) malloc(lutsize * sizeof(uint32_t));
getMin(5, ptr);
}
It seems to me that, not having all the possible permutations, you need to check all of those you have. Calculating the best permutation is not fruitful if you aren't sure that permutation is available.
So, the two optimizations remaining you can hope for are:
Stop the search if you achieve a minimum.
For example, if I have understood, you have the binary number 11001101. What is the minimum permutation value? Obviously 00011111, with all ones to the right. What exact permutation does this for you - whether the last 1 is the first, second, fifth, sixth or eight bit - matters not to you.
As soon as a permutation hits the magic value, that is the minimum and you know you can do no better, so you can just as well stop searching.
In your own example you hit the minimum value 3 (or 0011, which is the minimum from 1001 or 5) at iteration 4. You gained nothing from iterations five to seven.
If you have 1101, Go from { 0, 1, 3, 2 } to the bit-permutated value "1110" as fast as possible.
Not sure about the performances, but you could try precalculating the values from the table, even if this requires a 32x32 = 1024 32-value table - 4M of memory.
Considering the first position (our number is 1101), the permutation can have in position 0 only these values: 0, 1, 2, or 3. These have a value of 1___, 1___, 0___ or 1___. So our position 0 table is { 1000, 1000, 0000, 1000 }.
The second position is identical: { 1_, 1_, 0_, 1_ } and so we have { 0100, 0100, 0000, 0100 }.
The next two rows are { 0010, 0010, 0000, 0010 }
{ 0001, 0001, 0000, 0001 }.
Now, you want to calculate the value if permutation { 3, 0, 1, 2 } is applied:
for (i = 0; i < 4; i++) {
value |= table[i][permutation[i]];
}
===
But (again, if I understood the problem), let us say that the number has one fourth zeroes (it is made up of 24 1's, 8 0's) and the table is sizeable enough.
There is a very significant chance that you very soon hit both a permutation that puts a bit 1 in the 31st position, yielding some 2 billion, and another that puts a 0 there, yielding one billion.
The minimum will then surely be below two billions, so from now on, as soon as you check the first permutated bit and find it is a 1, you can stop calculating, you won't get a better minimum out of that permutation. Skip immediately to the next.
If you do this check at every cycle instead of only the first,
for (i = 0; i < 4; i++) {
value |= table[i][permutation[i]];
if (value > minimum) {
break;
}
}
I fear that you might eat any gains, but on the other hand, since values are automatically ordered in descending order, the first bits would get eliminated the most, avoiding the subsequent checks. It might be worth checking.
Nothing stops you from doing the calculation in two steps:
for (i = 0; i < 8; i++) {
value |= table[i][permutation[i]];
if (value > minimum) {
break;
}
}
if (value < minimum) {
for (; i < 32; i++) {
value |= table[i][permutation[i]];
}
}
I have a sequence of arrays of numbers with 5 elements each, from 0 to 8, and I have to order than using that combination, I mean:
i=0, {0,0,0,0,0}
i=1, {0,0,0,0,1}
i=2, {0,0,0,0,2}
i=3, {0,0,0,0,3}
i=4, {0,0,0,0,4}
i=5, {0,0,0,0,5}
i=6, {0,0,0,0,6}
i=7, {0,0,0,0,7}
i=8, {0,0,0,0,8}
i=9, {0,0,0,1,1}
...
i=1285, {7,8,8,8,8}
i=1286, {8,8,8,8,8}
so if I give {0,0,1,1,2} to the function it's returns 7.
I thought about using the Combinatorial number system
but I'm missing something that I don't know what it is, the code below just doesn't work
#include <stdio.h>
#include <stdlib.h>
#define size 1287
int combination[9][5] = {
{0, 0, 0, 0, 0},
{1, 1, 1, 1, 1},
{2, 3, 4, 5, 6},
{3, 3, 6, 15, 21},
{4, 10, 20, 35, 56},
{5, 15, 35, 70, 126},
{6, 21, 56, 126, 252},
{7, 28, 84, 210, 462},
{8, 36, 120, 330, 792}
};
int getKey(int array[]){
int key=0;
int tempArray[9] = {0};
for(int i=0;i<5;i++){
tempArray[array[i]]++;
}
int j=0;
for(int i=0;i<9;i++){
if(tempArray[i]!=0){
while(tempArray[i]!=0){
array[j++] = i;
key += combination[i][5-j];
tempArray[i]--;
}
}
}
return key;
}
int main(){
int it[5];
for(it[0] = 0 ;it[0]<9;it[0]++){
for(it[1]=it[0];it[1]<9;it[1]++){
for(it[2]=it[1];it[2]<9;it[2]++){
for(it[3]=it[2];it[3]<9;it[3]++){
for(it[4]=it[3];it[4]<9;it[4]++){
printf("{%d %d %d %d %d} = %d\n",it[0],it[1],it[2],it[3],it[4],getKey(it));
}
}
}
}
}
return 0;
}
Obs: I'm using counting sort to keep the lexicographic order, in theory I will receive unsorted arrays.
I will give you the Answer I wrote for the previous version of this question which you posted yesterday and deleted. (And that's bad form, by the way.)
Let's call the binomial coefficient C(n, k) = n!/(k!(n-k)!)
The number of unordered strings of m letters drawn from an alphabet of s symbols is C(m+s-1, s-1). Let's call that D(m, s). In this case, D(5, 9) = C(5+9-1, 9-1) = C(13, 8) = 1287
Let's sort each string, then number them:
aaaaa 1
aaaab 2
aaaac 3
...
aaaai 9
aaabb 10
aaabc 11
...
If a string contains 5 a's, its number is D(5, 1) = C(5+1-1, 1-1) = C(5, 0) = 1.
If a string contains 4 a's, its number is 1 plus a number determined by the non-a letter, which goes up to D(1,8) = C(1+8-1,8-1) = C(8, 7) = 8. So they go up to 1+8=9.
If a string contains 3 a's, its number is 9 plus a number determined by the non-a letters, which goes up to D(2,8) = C(9,7) = 36, so 9+36=45.
If a string contains 2 a's, its number is in [46,165].
If a string contains 1 a, its number is in [166, 495].
If a string contains no a, its number is in [496, 1287].
So how about the string "aabgg"? It's number is (45)+(8)+(7)+(6)+(5)+(4)+(1)=76
No collisions, and the calculation of the index is O(sm(s+m)), which is not too bad for m=5 and s=9.
EDIT: to clarify, let's define
E(j, m, s) = D(0,s-1)+D(1,s-1)+...+D(m-j-1,s-1)
Suppose a string of m letters drawn from an alphabet of s symbols contains j of the first letter of the alphabet. There are E(j,m,s) strings in the catalogue before the first such string. For instance, before the first string that begins with exactly two a's ("aabbb"), there are E(2, 5, 9)=45 strings.
To get to "aabbb" we must count out 45 strings.
To get from "aabbb" to the next string that contains exactly one b ("aabcc"), we must count out E(1, 3, 8) = 8 strings.
From there to the next string that contains no c ("aabdd"), E(0, 2, 7) = 7 strings.
No d ("aabee"): E(0, 2, 6) = 6
No e ("aabff"): E(0, 2, 5) = 5
No f ("aabgg"): E(0, 2, 4) = 4
And we must count "aabgg" itself: 1
well, I think this look like oct number 1...8
0 = {00000}
1 = {00001}
2 = {00002}
8 = {00010}
if this what you mean
I think this algorithm is the best
int get_key(int a[5]){
int idx, rval=0;
for(i=4; i<=0; i--)
rval += powl(a[i], i);
return rval;
}
This is my code initializing the array:
#include <stdio.h>
int main (void) {
int x, n;
// 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
int *array = {2, 4, 6, 9, 11, 13, 15, 17, 19, 21, 25, 29, 30, 34, 35, 38};
n = sizeof(array) / sizeof(int);
for (x=0; x<n; x++) {
printf("%i: %i - ", x, array[x]);
}
printf("\nArray's length: %i", n);
return 0;
}
I'm not understanding why this simple code shows this message:
Runtime error
Thanks in advance.
Change this:int *array = to this: int array[] =. Ideone link: https://ideone.com/ULH7i6 . See this too: How to initialize all members of an array to the same value?
What did you have in mind when you declared the following line?
int *array = {2, 4, 6, 9, 11, 13, 15, 17, 19, 21, 25, 29, 30, 34, 35, 38};
What comes to mind when I see something like this you're trying to work with an array using pointer arithmetic, which makes for a lot of fun interview questions (and just cool in general :P ). On the other hand you might just be used to being able to create arrays using array literals.
Below is something that talks about the different types of arrays you might be trying to work with. I know you picked an answer but this might be useful to you if you were trying to accomplish something else.
C pointer to array/array of pointers disambiguation
Your array declaration is not correct.... just edit your declaration to
int *array[] = {2, 4, 6, 9, 11, 13, 15, 17, 19, 21, 25, 29, 30, 34, 35, 38};
here the correction code!
#include <stdio.h>
int main (void) {
int x, n;
// 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
int *array[] = {2, 4, 6, 9, 11, 13, 15, 17, 19, 21, 25, 29, 30, 34, 35, 38};
n =sizeof(array) / sizeof(int);
for (x=0; x<n; x++) {
printf("%i: %i - ",x,array[x]);
}
printf("\nArray's length: %i", n);
return 0;
}
Using a microcontroller (PIC18F4580), I need to collect data and send it to an SD card for later analysis. The data it collects will have values between 0 and 1023, or 0x0 and 0x3FF.
So what I need to do is convert 1023 into a base 10 string of literal ASCII values (0x31, 0x30, 0x32, 0x33, ...).
My problem is that the only way I can think of to split the digits apart requires a lot of division.
char temp[4];
temp[0] = 1023 % 10;
temp[1] = (1023 % 100) / 10;
temp[2] = (1023 % 1000) / 100;
temp[3] = (1023 % 10000) / 1000;
Using this method, finding the ASCII values of an n digit decimal number requires 2n-1 divisions. Is there a method that would be faster?
The end goal of this is to wind up with a .csv file on the SD card that can quickly be plugged into any laptop to see a graph of the data in Excel.
The obvious solution is not to convert the data to ASCII at all but store it in binary format. That way all you need to worry about is the endianness of the data. If the system performing the later analysis is far more powerful than your embedded target, then it would make sense to let that deal with the conversion and and byte order.
On the other hand, it is possible that the execution time of the / and % is insignificant compared to the time taken to transfer the data to the SD card; so make sure that you are optimising the right thing.
There's certainly a much faster way: have an array of 1024 pre-computed strings. Then you can just do bounds checking, followed by an index into the array.
It's unclear from your question whether your code is running on the microcontroller though. If that's the case, you may not have enough memory for this approach.
I agree with what Clifford said, that you shouldn't worry about optimizing it if you don't have to, and that you can push the log cleanup to your analysis platform, rather than worrying about formatting in an embedded application.
That being said, here's an article that might be useful to you. It uses a loop, shifts, additions and branches, with linear/constant complexity: http://www.johnloomis.org/ece314/notes/devices/binary_to_BCD/bin_to_bcd.html
Also, I thought it would be fun to make some code that doesn't perform any divides, multiplies, or branches, but still gives the correct answer [0 - 1024). No promises that this is any faster than other options. This sort of code is just an option to explore.
I'd love to see if anyone can provide some tricks to make the code smaller, require less memory, or require fewer operations, while keeping the rest of the counts equal, or shrinking them :)
Stats:
224 bytes in constants (no idea on the code size)
5 bit-shift-rights
3 subtracts
5 bitwise-ands
4 bitwise-ors
1 greater-than comparison
Perf:
Using the perf comparisons and itoa routines in Jonathan Leffler's answer, here are the stats I got:
Division 2.15
Subtraction 4.87
My solution 1.56
Brute force lookup 0.36
I increased the iteration count to 200000 to ensure I didn't have any problems with timing resolution, and had to add volatile to the function signatures so that the compiler didn't optimize out the loop. I used VS2010 express w/ vanilla "release" settings, on a 3ghz dual core 64 bit Windows 7 machine (tho it compiled to 32 bit).
The code:
#include "stdlib.h"
#include "stdio.h"
#include "assert.h"
void itoa_ten_bits(int n, char s[])
{
static const short thousands_digit_subtract_map[2] =
{
0, 1000,
};
static const char hundreds_digit_map[128] =
{
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
0, 0, 0,
};
static const short hundreds_digit_subtract_map[10] =
{
0, 100, 200, 300, 400, 500, 600, 700, 800, 900,
};
static const char tens_digit_map[12] =
{
0, 1, 2, 3, 3, 4, 5, 6, 7, 7, 8, 9,
};
static const char ones_digit_map[44] =
{
0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
0, 1, 2, 3
};
/* Compiler should optimize out appX constants, % operations, and + operations */
/* If not, use this:
static const char ones_digit_append_map[16] =
{
0, 6, 2, 8, 4, 10, 6, 12, 8, 14, 10, 16, 12, 18, 14, 20,
};
*/
static const char a1 = 0x10 % 10, a2 = 0x20 % 10, a3 = 0x40 % 10, a4 = 0x80 % 10;
static const char ones_digit_append_map[16] =
{
0, a1, a2, a1 + a2,
a3, a1 + a3, a2 + a3, a1 + a2 + a3,
a4, a1 + a4, a2 + a4, a1 + a2 + a4,
a3 + a4, a1 + a3 + a4, a2 + a3 + a4, a1 + a2 + a3 + a4,
};
char thousands_digit, hundreds_digit, tens_digit, ones_digit;
assert(n >= 0 && n < 1024 && "n must be between [0, 1024)");
/* n &= 0x3ff; can use this instead of the assert */
thousands_digit = (n >> 3 & 0x7f) > 0x7c;
n -= thousands_digit_subtract_map[thousands_digit];
ones_digit = ones_digit_map[
(n & 0xf)
+ ones_digit_append_map[n >> 4 & 0xf]
+ ones_digit_append_map[n >> 8 & 0x3]
];
n -= ones_digit;
hundreds_digit = hundreds_digit_map[n >> 3 & 0x7f];
n -= hundreds_digit_subtract_map[hundreds_digit];
tens_digit = tens_digit_map[n >> 3];
s[0] = '0' | thousands_digit;
s[1] = '0' | hundreds_digit;
s[2] = '0' | tens_digit;
s[3] = '0' | ones_digit;
s[4] = '\0';
}
int main(int argc, char* argv)
{
int i;
for(i = 0; i < 1024; ++i)
{
char blah[5];
itoa_ten_bits(i, blah);
if(atoi(blah) != i)
printf("failed %d %s\n", i, blah);
}
}
There's a way of doing it using subtractions, but I am not convinced it's faster than using subtractions and modulus on a "normal" CPU (may be different in an embedded environment).
Something like this:
char makedigit (int *number, int base)
{
static char map[] = "0123456789";
int ix;
for (ix=0; *number >= base; ix++) { *number -= base; }
return map[ix];
}
char *makestring (int number)
{
static char tmp[5];
tmp[0] = makedigit(&number, 1000);
tmp[1] = makedigit(&number, 100);
tmp[2] = makedigit(&number, 10);
tmp[3] = makedigit(&number, 1);
tmp[4] = '\0';
return tmp;
}
Then, a call to makestring() should result in a (static, so copy it before overwriting) string with the converted number (zero-prefixed, at 4 characters width, as the original assumption is a value in the 0-1023 range).
With some care in finding the right number(s) to use, you can multiply by the reciprocal of the base rather than dividing by the base. Terje's code is for an x86, but porting the general idea to a PIC shouldn't be tremendously difficult.
If the values are correctly in range (0..1023), then your last conversion is unnecessarily wasteful on the divisions; the last line could be replaced with:
temp[3] = 1023 / 1000;
or even:
temp[3] = 1023 >= 1000;
Since division is repeated subtraction, but you have a very special case (not a general case) division to deal with, I'd be tempted to compare the timings for the following code with the division version. I note that you put the digits into the string in 'reverse order' - the least significant digit goes in temp[0] and the most in temp[4]. Also, there is no chance of null-terminating the string given the storage. This code uses a table of 8 bytes of static data - considerably less than many of the other solutions.
void convert_to_ascii(int value, char *temp)
{
static const short subtractors[] = { 1000, 100, 10, 1 };
int i;
for (i = 0; i < 4; i++)
{
int n = 0;
while (value >= subtractors[i])
{
n++;
value -= subtractors[i];
}
temp[3-i] = n + '0';
}
}
Performance testing - Intel x86_64 Core 2 Duo 3.06 GHz (MacOS X 10.6.4)
This platform is probably not representative of your microcontroller, but the test shows that on this platform, the subtraction is considerably slower than the division.
void convert_by_division(int value, char *temp)
{
temp[0] = (value % 10) + '0';
temp[1] = (value % 100) / 10 + '0';
temp[2] = (value % 1000) / 100 + '0';
temp[3] = (value % 10000) / 1000 + '0';
}
void convert_by_subtraction(int value, char *temp)
{
static const short subtractors[] = { 1000, 100, 10, 1 };
int i;
for (i = 0; i < 4; i++)
{
int n = 0;
while (value >= subtractors[i])
{
n++;
value -= subtractors[i];
}
temp[3-i] = n + '0';
}
}
#include <stdio.h>
#include <timer.h>
#include <string.h>
static void time_convertor(const char *tag, void (*function)(void))
{
int r;
Clock ck;
char buffer[32];
clk_init(&ck);
clk_start(&ck);
for (r = 0; r < 10000; r++)
(*function)();
clk_stop(&ck);
printf("%s: %12s\n", tag, clk_elapsed_us(&ck, buffer, sizeof(buffer)));
}
static void using_subtraction(void)
{
int i;
for (i = 0; i < 1024; i++)
{
char temp1[4];
convert_by_subtraction(i, temp1);
}
}
static void using_division(void)
{
int i;
for (i = 0; i < 1024; i++)
{
char temp1[4];
convert_by_division(i, temp1);
}
}
int main()
{
int i;
for (i = 0; i < 1024; i++)
{
char temp1[4];
char temp2[4];
convert_by_subtraction(i, temp1);
convert_by_division(i, temp2);
if (memcmp(temp1, temp2, 4) != 0)
printf("!!DIFFERENCE!! ");
printf("%4d: %.4s %.4s\n", i, temp1, temp2);
}
time_convertor("Using division ", using_division);
time_convertor("Using subtraction", using_subtraction);
time_convertor("Using division ", using_division);
time_convertor("Using subtraction", using_subtraction);
time_convertor("Using division ", using_division);
time_convertor("Using subtraction", using_subtraction);
time_convertor("Using division ", using_division);
time_convertor("Using subtraction", using_subtraction);
return 0;
}
Compiling with GCC 4.5.1, and working in 32-bit, the average timings were (optimization '-O'):
0.13 seconds using division
0.65 seconds using subtraction
Compiling and working in 64-bit, the average timings were:
0.13 seconds using division
0.48 seconds using subtraction
Clearly, on this machine, using subtraction is not a winning proposition. You would have to measure on your machine to make a decision. And removing the modulo 10000 operation will only skew results in favour of the division (it knocks about 0.02 seconds off the time with division when replaced with the comparison; that's a 15% saving and worth having).
Is there some reason that you're particularly concerned about this?
If your compiler and C library provide an itoa() function, use that, and then worry about writing this code (and associated tests and so forth to make sure you got it right!) if for some reason that turns out to be too slow or doesn't fit into RAM or something.
I've replaced my previous answer with a better one. This code creates a 4-character string in the proper order, most significant digit in output[0] to least significant in output[3] with a zero terminator in output[4]. I don't know anything about your PIC controller or C compiler, but this code doesn't require anything more than 16-bit integers, addition/subtraction, and shifting.
int x;
char output[5];
output[4] = 0;
x = 1023;
output[3] = '0' + DivideByTenReturnRemainder(&x);
output[2] = '0' + DivideByTenReturnRemainder(&x);
output[1] = '0' + DivideByTenReturnRemainder(&x);
output[0] = '0' + x;
The key to this is the magical function DivideByTenReturnRemainder. Without using division explicitly it's still possible to divide by powers of 2 by shifting right; the problem is that 10 isn't a power of 2. I've sidestepped that problem by multiplying the value by 25.625 before dividing by 256, letting integer truncation round down to the proper value. Why 25.625? Because it's easily represented by powers of 2. 25.625 = 16 + 8 + 1 + 1/2 + 1/8. Again, multiplying by 1/2 is the same as shifting right one bit, and multiplying by 1/8 is shifting right by 3 bits. To get the remainder, multiply the result by 10 (8+2) and subtract it from the original value.
int DivideByTenReturnRemainder(int * p)
{
/* This code has been tested for an input range of 0 to 1023. */
int x;
x = *p;
*p = ((x << 4) + (x << 3) + x + (x >> 1) + (x >> 3)) >> 8;
return x - ((*p << 3) + (*p << 1));
}
Are you required to use an ASCII string of the decimal representation? It would be much easier to store it in hexadecimal format. No division required, only (relatively cheap) shift operations. Excel should be able to read it if you prepend a '0x' to each number.
I have a 5-digit integer, say
int num = 23456;
How to find the sum of its digits?
Use the modulo operation to get the value of the least significant digit:
int num = 23456;
int total = 0;
while (num != 0) {
total += num % 10;
num /= 10;
}
If the input could be a negative number then it would be a good idea to check for that and invert the sign.
#include <stdio.h>
int main()
{
int i = 23456;
int sum = 0;
while(i)
{
sum += i % 10;
i /= 10;
}
printf("%i", sum);
return 0;
}
int sum=0;while(num){sum+=num%10;num/=10;}
Gives a negative answer if num is negative, in C99 anyway.
Is this homework?
How about this:
for(sum=0 ,num=23456;num; sum+=num %10, num/=10);
If you want a way to do it without control statements, and incredibly efficient to boot, O(1) instead of the O(n), n = digit count method:
int getSum (unsigned int val) {
static int lookup[] = {
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, // 0- 9
1, 2, 3, 4, 5, 6, 7, 8, 9, 10, // 10- 19
2, 3, 4, 5, 6, 7, 8, 9, 10, 11, // 20- 29
:
9, 10, 11, 12, 13, 14, 15, 16, 17, 18, // 90- 99
:
14, 15, 16, 17, 18, 19, 20, 21, 22, 23, // 23450-23459
::
};
return lookup[23456];
}
:-)
Slightly related: if you want the repeated digit sum, a nice optimization would be:
if (num%3==0) return (num%9==0) ? 9 : 3;
Followed by the rest of the code.
Actually, I answered with another (somewhat humorous) answer which used a absolutely huge array for a table lookup but, thinking back on it, it's not that bad an idea, provided you limit the table size.
The following functions trade off space for time. As with all optimisations, you should profile them yourself in the target environment.
First the (elegant) recursive version:
unsigned int getSum (unsigned int val) {
static const unsigned char lookup[] = {
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, // 0- 9
1, 2, 3, 4, 5, 6, 7, 8, 9, 10, // 10- 19
2, 3, 4, 5, 6, 7, 8, 9, 10, 11, // 20- 29
:
18, 19, 20, 21, 22, 23, 24, 25, 26, 27 // 990-999
};
return (val == 0) ? 0 : getSum (val / 1000) + lookup[val%1000];
}
It basically separates the number into three-digit groupings with fixed lookups for each possibility. This can easily handle a 64-bit unsigned value with a recursion depth of seven stack frames.
For those who don't even trust that small amount of recursion (and you should, since normal programs go that deep and more even without recursion), you could try the iterative solution:
unsigned int getSum (unsigned int val) {
static const unsigned char lookup[] = {
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, // 0- 9
1, 2, 3, 4, 5, 6, 7, 8, 9, 10, // 10- 19
2, 3, 4, 5, 6, 7, 8, 9, 10, 11, // 20- 29
:
18, 19, 20, 21, 22, 23, 24, 25, 26, 27 // 990-999
};
unsigned int tot = 0;
while (val != 0) {
tot += lookup[val%1000];
val /= 1000;
}
return tot;
}
These are probably three times faster than the one-digit-at-a-time solution, at the cost of a thousand bytes of data. If you're not adverse to using 10K or 100K, you could increase the speed to four or five times but you may want to write a program to generate the static array statement above :-)
As with all optimisation options, measure, don't guess!
I prefer the more elegant recursive solution myself but I'm also one of those types who prefer cryptic crosswords. Read into that what you will.
#include <stdio.h>
2 #include <stdlib.h>
3
4 #define BUFSIZE 20
5
6 int main(void)
7 {
8 int number = 23456;
9 char myBuf[BUFSIZE];
10 int result;
11 int i = 0;
12
13 sprintf(myBuf,"%i\0",number);
14
15 for( i = 0; i < BUFSIZE && myBuf[i] != '\0';i++)
16 {
17 result += (myBuf[i]-48);
18 }
19
20 printf("The result is %d",result);
21 return 0;
22 }
23
Another idea here using the sprintf and the ascii number representation
#include<stdio.h>
main()
{
int sum=0,n;
scanf("%d",&n);
while(n){
sum+=n%10;
n/=10;
}
printf("result=%d",sum);
}
sum is the sum of digits of number n