There is an algorithm for a FIR filter but it's floatingpoint:
FIR filter implementation in C programming
If I want a fixedpoint algorithm with this spec, how would I do it?
the FIR-filter receives and sends 8-bit fixed-point numbers in the
Q7-format via the standard input and output. Remember to output the
measured time (number of ticks) also in hex format. Following the
guidelines presented in the previous section, your program should call
getchar() to read a Q7-value. should call putchar() to write a
Q7-value.
The coefficients are
c0=0.0299 c1=0.4701 c2=0.4701 c3=0.299
And for a fixedpoint algorithm I would need to implement my own multiplication for fixedpoint number, right?
Should I store a fixepdpoint number like a struct i.e.
struct point
{
int integer;
int fraction;
};
Should I use shifts to implement the numbering and specifically how?
The number are 32-bit so could I write the shifts like below?
#define SHIFT_AMOUNT 16 // 2^16 = 65536
#define SHIFT_MASK ((1 << SHIFT_AMOUNT) - 1)
So I think that I must implement one multiplication algorithm and then the FIR algorithm itself? Is that correct? Can you help me?
Update
I compiled and ran a program like in the anser but it's giving me unexpected output.
#include <stdio.h>
#include "system.h"
#define FBITS 16 /* number of fraction bits */
const int c0 = (( 299<<FBITS) + 5000) / 10000; /* (int)(0.0299*(1<<FBITS) + 0.5) */
const int c1 = ((4701<<FBITS) + 5000) / 10000; /* (int)(0.4701*(1<<FBITS) + 0.5) */
/* Ditto for C3 and C2 */
const int c2 = (( 4701<<FBITS) + 5000) / 10000; /* (int)(0.4701 *(1<<FBITS) + 0.5) */
const int c3 = ((299<<FBITS) + 5000) / 10000; /* (int)(0.299*(1<<FBITS) + 0.5) */
#define HALF (1 << (FBITS) >> 1) /* Half adjust for rounding = (int)(0.5 * (1<<FBITS)) */
signed char input[4]; /* The 4 most recent input values */
int output = 0;
void firFixed()
{
signed char sum = c0*input[0] + c1*input[1] + c2*input[2] + c3*input[3];
output = (signed char)((sum + HALF) >> FBITS);
printf("output: %d\n", output);
}
int main( void )
{
int i=0;
signed char inVal;
while (scanf("%c", &inVal) > 0)
{
if (i>3)
{
i=0;
}
input[i]=inVal;
firFixed();
i++;
}
return 0;
}
Why is output not computed correctly andd why is output written several times after one input?
Update
I tried writing the fixedpoint FIR filter, the algorithm might not be 100 % correct:
#include <stdio.h>
#include "system.h"
#define FBITS 16 /* number of fraction bits */
const int c0 = (( 299<<FBITS) + 5000) / 10000; /* (int)(0.0299*(1<<FBITS) + 0.5) */
const int c1 = ((4701<<FBITS) + 5000) / 10000; /* (int)(0.4701*(1<<FBITS) + 0.5) */
/* Ditto for C3 and C2 */
const int c2 = (( 4701<<FBITS) + 5000) / 10000; /* (int)(0.4701 *(1<<FBITS) + 0.5) */
const int c3 = ((299<<FBITS) + 5000) / 10000; /* (int)(0.299*(1<<FBITS) + 0.5) */
#define HALF (1 << (FBITS) >> 1) /* Half adjust for rounding = (int)(0.5 * (1<<FBITS)) */
signed char input[4]; /* The 4 most recent input values */
char get_q7( void );
void put_q7( char );
void firFixed()
{
int sum = c0*input[0] + c1*input[1] + c2*input[2] + c3*input[3];
signed char output = (signed char)((sum + HALF) >> FBITS);
put_q7(output);
}
int main( void )
{
int i=0;
while(1)
{
if (i>3)
{
i=0;
}
input[i]=get_q7();
firFixed();
i++;
}
return 0;
}
#include <sys/alt_stdio.h>
char get_q7( void );
char prompt[] = "Enter Q7 (in hex-code): ";
char error1[] = "Illegal hex-code - character ";
char error2[] = " is not allowed";
char error3[] = "Number too big";
char error4[] = "Line too long";
char error5[] = "Line too short";
char get_q7( void )
{
int c; /* Current character */
int i; /* Loop counter */
int num;
int ok = 0; /* Flag: 1 means input is accepted */
while( ok == 0 )
{
num = 0;
for( i = 0; prompt[i]; i += 1 )
alt_putchar( prompt[i] );
i = 0; /* Number of accepted characters */
while( ok == 0 )
{
c = alt_getchar();
if( c == (char)26/*EOF*/ ) return( -1 );
if( (c >= '0') && (c <= '9') )
{
num = num << 4;
num = num | (c & 0xf);
i = i + 1;
}
else if( (c >= 'A') && (c <= 'F') )
{
num = num << 4;
num = num | (c + 10 - 'A');
i = i + 1;
}
else if( (c >= 'a') && (c <= 'f') )
{
num = num << 4;
num = num | (c + 10 - 'a');
i = i + 1;
}
else if( c == 10 ) /* LF finishes line */
{
if( i > 0 ) ok = 1;
else
{ /* Line too short */
for( i = 0; error5[i]; i += 1 )
alt_putchar( error5[i] );
alt_putchar( '\n' );
break; /* Ask for a new number */
}
}
else if( (c & 0x20) == 'X' || (c < 0x20) )
{
/* Ignored - do nothing special */
}
else
{ /* Illegal hex-code */
for( i = 0; error1[i]; i += 1 )
alt_putchar( error1[i] );
alt_putchar( c );
for( i = 0; error2[i]; i += 1 )
alt_putchar( error2[i] );
alt_putchar( '\n' );
break; /* Ask for a new number */
}
if( ok )
{
if( i > 10 )
{
alt_putchar( '\n' );
for( i = 0; error4[i]; i += 1 )
alt_putchar( error4[i] );
alt_putchar( '\n' );
ok = 0;
break; /* Ask for a new number */
}
if( num >= 0 && num <= 255 )
return( num );
for( i = 0; error3[i]; i += 1 )
alt_putchar( error3[i] );
alt_putchar( '\n' );
ok = 0;
break; /* Ask for a new number */
}
}
}
return( 0 ); /* Dead code, or the compiler complains */
}
#include <sys/alt_stdio.h>
void put_q7( char ); /* prototype */
char prom[] = "Calculated FIR-value in Q7 (in hex-code): 0x";
char hexasc (char in) /* help function */
{
in = in & 0xf;
if (in <=9 ) return (in + 0x30);
if (in > 9 ) return (in - 0x0A + 0x41);
return (-1);
}
void put_q7( char inval)
{
int i; /* Loop counter */
for( i = 0; prom[i]; i += 1 )
alt_putchar( prom[i] );
alt_putchar (hexasc ((inval & 0xF0) >> 4));
alt_putchar (hexasc (inval & 0x0F));
alt_putchar ('\n');
}
Each point in the FIR filter result is just a weighted sum of values from the unfiltered data. You shouldn't need anything other than plain multiplication and addition if you have 8-bit input data and 32-bit arithmetic.
A quick visit to Wikipedia tells me that Q7 is essentially an 8-bit 2's complement integer, so if the target platform uses 2's complement, then simply describing the byte received as (signed char) will give it the correct numerical value when promoted to an int. If you premultiply the coefficients by a power of two, then the weighted sum will be multiplied by that same power of 2. Rounded division is then simply adding a half-adjust value followed by a signed right shift. With 16-bit fractions, the premultiplied constants are:
#define FBITS 16 /* number of fraction bits */
const int C0 = (( 299<<FBITS) + 5000) / 10000; /* (int)(0.0299*(1<<FBITS) + 0.5) */
const int C1 = ((4701<<FBITS) + 5000) / 10000; /* (int)(0.4701*(1<<FBITS) + 0.5) */
/* Ditto for C3 and C2 */
#define HALF (1 << (FBITS) >> 1) /* Half adjust for rounding = (int)(0.5 * (1<<FBITS)) */
The reason for that oddness it to get the significant bits you want without depending on any floating point rounding. Now, if:
signed char input[4];
...contain the 4 most recent input values, your output value is:
sum = c0*input[0] + c1*input[1] + c2*input[2] + c3*input[3];
output = (signed char)((sum + HALF) >> FBITS);
Since all of your coefficients are positive and sum to 1.0, there's no possibility of overflow.
There are a number of optimizations you can try after you get a simple version working. One possible minor glitch with other coefficients is for that rounding of the C0-C3 constants to produce values that don't exactly add up to 1<<FBITS. I tested and it doesn't happen with these values (you'd need the c0*(1<<LBITS) to have a fraction part of exactly 0.5; meaning that all the other scaled coefficients would also have 0.5 as their fraction parts. They'd all round up and the sum would be too large by 2. That could add a very small unintended gain to your filter.
That can't occur with the coefficients you gave.
Edit: I forgot. Both the integer part and fraction part are in the same 32-bit int during the sum calculation. With 8 bits of input(7+sign) and 16 bits of fraction, you can have up to 2^(32 - 16 - 8) = 2^8 = 256 points in the filter (at this point, you will obviously have an array of coefficients, and a multiply-add loop to compute the sum. Should the (input size) + (fraction bits) + log2(filter size) exceed 32, then you can try to expand the sum field to a C99 long long or int64_t value, if that's available, or write extended-precision add and shift logic if not. Extended precision in hardware is far better to use, when available.
Related
I'm trying to make a get_random_4digit function that generates a 4 digit number that has non-repeating digits ranging from 1-9 while only using ints, if, while and functions, so no arrays etc.
This is the code I have but it is not really working as intended, could anyone point me in the right direction?
int get_random_4digit() {
int d1 = rand() % 9 + 1;
int d2 = rand() % 9 + 1;
while (true) {
if (d1 != d2) {
int d3 = rand() % 9 + 1;
if (d3 != d1 || d3 != d2) {
int d4 = rand() % 9 + 1;
if (d4 != d1 || d4 != d2 || d4 != d3) {
random_4digit = (d1 * 1000) + (d2 * 100) + (d3 * 10) + d4;
break;
}
}
}
}
printf("Random 4digit = %d\n", random_4digit);
}
A KISS-approach could be this:
int getRandom4Digits() {
uint16_t acc = 0;
uint16_t used = 0;
for (int i = 0; i < 4; i++) {
int idx;
do {
idx = rand() % 9; // Not equidistributed but never mind...
} while (used & (1 << idx));
acc = acc * 10 + (idx + 1);
used |= (1 << idx);
}
return acc;
}
This looks terribly dumb at first. A quick analysis gives that this really isn't so bad, giving a number of calls to rand() to be about 4.9.
The expected number of inner loop steps [and corresponding calls to rand(), if we assume rand() % 9 to be i.i.d.] will be:
9/9 + 9/8 + 9/7 + 9/6 ~ 4.9107.
There are 9 possibilities for the first digit, 8 possibilities for the second digit, 7 possibilities for the third digit and 6 possibilities for the last digit. This works out to "9*8*7*6 = 3024 permutations".
Start by getting a random number from 0 to 3023. Let's call that P. To do this without causing a biased distribution use something like do { P = rand() & 0xFFF; } while(P >= 3024);.
Note: If you don't care about uniform distribution you could just do P = rand() % 3024;. In this case lower values of P will be more likely because RAND_MAX doesn't divide by 3024 nicely.
The first digit has 9 possibilities, so do d1 = P % 9 + 1; P = P / 9;.
The second digit has 8 possibilities, so do d2 = P % 8 + 1; P = P / 8;.
The third digit has 7 possibilities, so do d3 = P % 7 + 1; P = P / 7;.
For the last digit you can just do d4 = P + 1; because we know P can't be too high.
Next; convert "possibility" into a digit. For d1 you do nothing. For d2 you need to increase it if it's greater than or equal to d1, like if(d2 >= d1) d2++;. Do the same for d3 and d4 (comparing against all previous digits).
The final code will be something like:
int get_random_4digit() {
int P, d1, d2, d3, d4;
do {
P = rand() & 0xFFF;
} while(P >= 3024);
d1 = P % 9 + 1; P = P / 9;
d2 = P % 8 + 1; P = P / 8;
d3 = P % 7 + 1; P = P / 7;
d4 = P + 1;
if(d2 >= d1) d2++;
if(d3 >= d1) d3++;
if(d3 >= d2) d3++;
if(d4 >= d1) d4++;
if(d4 >= d2) d4++;
if(d4 >= d3) d4++;
return d1*1000 + d2*100 + d3*10 + d4;
}
You could start with an integer number, 0x123456789, and pick random nibbles from it (the 4 bits that makes up one of the digits in the hex value). When a nibble has been selected, remove it from the number and continue picking from those left.
This makes exactly 4 calls to rand() and has no if or other conditions (other than the loop condition).
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
int get_random_4digit() {
uint64_t bits = 0x123456789; // nibbles
int res = 0;
// pick random nibbles
for(unsigned last = 9 - 1; last > 9 - 1 - 4; --last) {
unsigned lsh = last * 4; // shift last nibble
unsigned sel = (rand() % (last + 1)) * 4; // shift for random nibble
// multiply with 10 and add the selected nibble
res = res * 10 + ((bits & (0xFULL << sel)) >> sel);
// move the last unselected nibble right to where the selected
// nibble was:
bits = (bits & ~(0xFULL << sel)) |
((bits & (0xFULL << lsh)) >> (lsh - sel));
}
return res;
}
Demo
Another variant could be to use the same value, 0x123456789, and do a Fisher-Yates shuffle on the nibbles. When the shuffle is done, return the 4 lowest nibbles. This is more expensive since it randomizes the order of all 9 nibbles - but it makes it easy if you want to select an arbitrary amount of them afterwards.
Example:
#include <stdlib.h>
#include <stdint.h>
#include <stdio.h>
#include <time.h>
uint16_t get_random_4digit() {
uint64_t bits = 0x123456789; // nibbles
// shuffle the nibbles
for(unsigned idx = 9 - 1; idx > 0; --idx) {
unsigned ish = idx * 4; // index shift
// shift for random nibble to swap with `idx`
unsigned swp = (rand() % (idx + 1)) * 4;
// extract the selected nibbles
uint64_t a = (bits & (0xFULL << ish)) >> ish;
uint64_t b = (bits & (0xFULL << swp)) >> swp;
// swap them
bits &= ~((0xFULL << ish) | (0xFULL << swp));
bits |= (a << swp) | (b << ish);
}
return bits & 0xFFFF; // return the 4 lowest nibbles
}
The bit manipulation can probably be optimized - but I wrote it like I thought it so it's probably better for readability to leave it as-is
You can then print the value as a hex value to get the output you want - or extract the 4 nibbles and convert it for decimal output.
int main() {
srand(time(NULL));
uint16_t res = get_random_4digit();
// print directly as hex:
printf("%X\n", res);
// or extract the nibbles and multiply to get decimal result - same output:
uint16_t a = (res >> 12) & 0xF;
uint16_t b = (res >> 8) & 0xF;
uint16_t c = (res >> 4) & 0xF;
uint16_t d = (res >> 0) & 0xF;
uint16_t dec = a * 1000 + b * 100 + c * 10 + d;
printf("%d\n", dec);
}
Demo
You should keep generating digits until distinct one found:
int get_random_4digit() {
int random_4digit = 0;
/* We must have 4 digits number - at least 1234 */
while (random_4digit < 1000) {
int digit = rand() % 9 + 1;
/* check if generated digit is not in the result */
for (int number = random_4digit; number > 0; number /= 10)
if (number % 10 == digit) {
digit = 0; /* digit has been found, we'll try once more */
break;
}
if (digit > 0) /* unique digit generated, we add it to result */
random_4digit = random_4digit * 10 + digit;
}
return random_4digit;
}
Please, fiddle youself
One way to do this is to create an array with all 9 digits, pick a random one and remove it from the list.
Something like this:
uint_fast8_t digits[]={1,2,3,4,5,6,7,8,9}; //only 1-9 are allowed, 0 is not allowed
uint_fast8_t left=4; //How many digits are left to create
unsigned result=0; //Store the 4-digit number here
while(left--)
{
uint_fast8_t digit=getRand(9-4+left); //pick a random index
result=result*10+digits[digit];
//Move all digits above the selcted one 1 index down.
//This removes the picked digit from the array.
while(digit<8)
{
digits[digit]=digits[digit+1];
digit++;
}
}
You said you need a solution without arrays. Luckily, we can store up to 16 4 bit numbers in a single uint64_t. Here is an example that uses a uint64_t to store the digit list so that no array is needed.
#include <stdint.h>
#include <inttypes.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
unsigned getRand(unsigned max)
{
return rand()%(max+1);
}
//Creates a uint64_t that is used as an array.
//Use no more than 16 values and don't use values >0x0F
//The last argument will have index 0
uint64_t fakeArrayCreate(uint_fast8_t count, ...)
{
uint64_t result=0;
va_list args;
va_start (args, count);
while(count--)
{
result=(result<<4) | va_arg(args,int);
}
return result;
}
uint_fast8_t fakeArrayGet(uint64_t array, uint_fast8_t index)
{
return array>>(4*index)&0x0F;
}
uint64_t fakeArraySet(uint64_t array, uint_fast8_t index, uint_fast8_t value)
{
array = array & ~((uint64_t)0x0F<<(4*index));
array = array | ((uint64_t)value<<(4*index));
return array;
}
unsigned getRandomDigits(void)
{
uint64_t digits = fakeArrayCreate(9,9,8,7,6,5,4,3,2,1);
uint_fast8_t left=4;
unsigned result=0;
while(left--)
{
uint_fast8_t digit=getRand(9-4+left);
result=result*10+fakeArrayGet(digits,digit);
//Move all digits above the selcted one 1 index down.
//This removes the picked digit from the array.
while(digit<8)
{
digits=fakeArraySet(digits,digit,fakeArrayGet(digits,digit+1));
digit++;
}
}
return result;
}
//Test our function
int main(int argc, char **argv)
{
srand(atoi(argv[1]));
printf("%u\n",getRandomDigits());
}
You could use a partial Fisher-Yates shuffle on an array of 9 digits, stopping after 4 digits:
// Return random integer from 0 to n-1
// (for n in range 1 to RAND_MAX+1u).
int get_random_int(unsigned int n) {
unsigned int x = (RAND_MAX + 1u) / n;
unsigned int limit = x * n;
int s;
do {
s = rand();
} while (s >= limit);
return s / x;
}
// Return random 4-digit number from 1234 to 9876 with no
// duplicate digits and no 0 digit.
int get_random_4digit(void) {
char possible[9] = {1, 2, 3, 4, 5, 6, 7, 8, 9};
int result = 0;
int i;
// Uses partial Fisher-Yates shuffle.
for (i = 0; i < 4; i++) {
// Get random position rand_pos from remaining possibilities i to 8
// (positions before i contain previous selected digits).
int rand_pos = i + get_random_int(9 - i);
// Select digit from position rand_pos.
char digit = possible[rand_pos];
// Exchange digits at positions i and rand_pos.
possible[rand_pos] = possible[i];
possible[i] = digit; // not really needed
// Put selected digit into result.
result = result * 10 + digit;
}
return result;
}
EDIT: I forgot the requirement "while only using int's, if, while and functions, so no arrays etc.", so feel free to ignore this answer!
If normal C integer types are allowed including long long int, the get_random_4digit() function above can be replaced with the following to satisfy the requirement:
// Return random 4-digit number from 1234 to 9876 with no
// duplicate digits and no 0 digit.
int get_random_4digit(void) {
long long int possible = 0x123456789; // 4 bits per digit
int result = 0;
int i;
// Uses partial Fisher-Yates shuffle.
i = 0;
while (i < 4) {
// Determine random position rand_pos in remaining possibilities 0 to 8-i.
int rand_pos = get_random_int(9 - i);
// Select digit from position rand_pos.
int digit = (possible >> (4 * rand_pos)) & 0xF;
// Replace digit at position rand_pos with digit at position 0.
possible ^= ((possible ^ digit) & 0xF) << (4 * rand_pos);
// Shift remaining possible digits down one position.
possible >>= 4;
// Put selected digit into result.
result = result * 10 + digit;
i++;
}
return result;
}
There are multiple answers to this question already, but none of them seem to fit the requirement only using ints, if, while and functions. Here is a modified version of Pelle Evensen's simple solution:
#include <stdlib.h>
int get_random_4digit(void) {
int acc = 0, used = 0, i = 0;
while (i < 4) {
int idx = rand() % 9; // Not strictly uniform but never mind...
if (!(used & (1 << idx))) {
acc = acc * 10 + idx + 1;
used |= 1 << idx;
i++;
}
}
return acc;
}
I want to "convert" a decimal number to a hex number. Not like 10 -> A.
E.g.: 10 -> 0x10, 55 -> 0x55, 2021 -> 0x2021, ...
My input is an int.
I already heard something about it. You can get the first digit with modulo 10. E.g. 55 % 10 is 5. But I don't know how to get the other digits and how to put it together.
I am using this function for other purpose but I did some changes and its work fine.
you can use this :
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#define CHECK_ALPHA_HEX(REC_CHAR) (unsigned)('#' < REC_CHAR && REC_CHAR < 'G')
#define CHECK_NUM(REC_CHAR) (unsigned)('/' < REC_CHAR && REC_CHAR < ':')
void DEC_TO_HEX(int in, int *outval ) {
uint8_t tbuff[5];
uint8_t chr_count = 0;
uint8_t len = sprintf(tbuff,"%d",in);
while(chr_count < len) {
tbuff[chr_count] -= CHECK_NUM(tbuff[chr_count]) ? '0' : CHECK_ALPHA_HEX(tbuff[chr_count]) ? '7' : tbuff[chr_count];
*outval |= (tbuff[chr_count] << (4 *((len-1) - chr_count)));
chr_count++;
}
}
int main() {
int out = 0;
int in = 2021;
DEC_TO_HEX(in,&out);`
printf("%x",out);
}
https://godbolt.org/z/8T9Wqb87n
how to get the other digits
Remove the extracted digit from input.
Repeat the extraction of one digit, until there are no more digits in input.
how to put it together.
Learn C programming language. Write a program that implements the algorithm.
As I understand, an integer value has to be converted to another integer. From there it's just basic arithmetic, where the process generatally consists of:
Getting one digit from input.
Putting it in output.
Removing that digit from input.
shifting input & output to desired state
I came up with 3 separate such convert_* function implementations. First one is similar to common simple int->string conversion algorithms - it first converts the digits and that the results is "inverted". The second one extract the digits from propor position from input - getting the most significant base10 digit from input and moving between base10 digits of input. The third one, puts base10 digits on the end of hex number (startign from the mast significant base16 digit), and then shifts hex number to the right to handle 0x55000000 trailing zeros in result.
#include <limits.h>
#include <stdio.h>
const unsigned maxhexdigits = sizeof(unsigned) * CHAR_BIT / 4;
unsigned convert_andrevert(unsigned n) {
unsigned o = 0;
unsigned hexdigits = 0;
// Convert hex digits from "the back"
while (n && hexdigits != maxhexdigits) {
o <<= 4;
o += n % 10;
n /= 10;
++hexdigits;
}
const unsigned swaps = hexdigits / 2;
//printf("a %#x %d %d \n", o, hexdigits, swaps);
// Invert hex digits
for (unsigned i = 0; i < swaps; ++i) {
const unsigned m1 = 0xFu << (i * 4);
const unsigned m2 = 0xFu << ((hexdigits - i - 1) * 4);
const unsigned road = (hexdigits - i * 2 - 1) * 4;
// extract bits m1
unsigned t = (o & m1) << road;
//printf("b o=%#x i=%#x 1=%#x m2=%#x t=%#x road=%d\n", o, i, m1, m2, t, road);
// set bit m1 in place of m2
o = (o & ~m1) | ((o & m2) >> road);
// set bit m2 in place of m1
o = (o & ~m2) | t;
}
return o;
}
unsigned mypow10u(unsigned i) {
unsigned r = 1;
while (i--) {
r *= 10;
}
return r;
}
unsigned convert_frommax(unsigned n) {
n %= mypow10u(maxhexdigits);
unsigned o = 0;
// always start from the maximuim digit, because
// we know it's location.
for (int i = maxhexdigits - 1; i >= 0; --i) {
o <<= 4;
//printf("o=%#x u=%d pow10u(i)=%u digit=%u rest=%u\n",
//o, i, mypow10u(i),
//n / mypow10u(i),
//n % mypow10u(i));
// extract leading base10 digit
o += n / mypow10u(i);
n %= mypow10u(i);
}
return o;
}
unsigned convert_andshift(unsigned n) {
unsigned o = 0;
unsigned hexdigits = 0;
// Convert hex digits from "the back"
// put put them from the front.
while (n && hexdigits != maxhexdigits) {
o >>= 4;
o += (n % 10) << (maxhexdigits * 4 - 4);
//printf("o=%#x %d\n", o, n%10);
n /= 10;
++hexdigits;
}
// Shift right to handle leading (trailing?) zeros.
o >>= ((maxhexdigits - hexdigits) * 4);
return o;
}
void testin(unsigned r, unsigned rr) {
printf(" -> %#x %s", rr, r == rr ? "OK" : "FAIL");
}
void TEST(unsigned a, unsigned r) {
printf("%u", a);
testin(r, convert_andrevert(a));
testin(r, convert_frommax(a));
testin(r, convert_andshift(a));
printf("\n");
}
int main() {
TEST(1, 0x1);
TEST(55, 0x55);
TEST(123, 0x123);
TEST(2021, 0x2021);
TEST(12345678, 0x12345678);
}
From basic profiling, convert_andshift is the fastest function.
Here is an approach:
#include<stdio.h>
int main()
{
int num = 0;
char cNumHex[20];
puts("Enter a decimal formed hex number: ");
scanf("%d",&num);
sprintf(cNumHex, "0x%d", num);
printf("\nThe entered as hex: %s\n", cNumHex);
return 0;
}
The output:
Enter a decimal formed hex number:
49478
The entered as hex: 0x49478
I program that I would like to convert an array of big-endian (I believe that since I'm on a Mac, ints would be little-endian) chars (or rather uint8_ts) to an int64_t and back. Here is my code:
int64_t CharsToInt(uint8_t* chars) {
return chars[0] + (chars[1] * 0x100) + (chars[2] * 0x10000) + (chars[3] * 0x1000000) + (chars[4] * 0x100000000) + (chars[5] * 0x10000000000) + (chars[6] * 0x1000000000000) + (chars[7] * 0x100000000000000);
}
void IntToChars(int64_t i, uint8_t* chars) {
for(int k = 0; k < 8; k++) {
chars[k] = i >> k*8;
}
}
int main() {
int64_t x;
unsigned char chars[8];
IntToChars(x, chars);
for (int k = 0; k < 8; k++) {
printf("%0x\n", chars[k]);
}
// little endian
int64_t rv = CharsToInt(chars);
printf("%lld\n", rv);
}
If x is 12, or any other zero or positive number, the code works perfectly fine, however if x is a negative number, it fails to work.
Output for x = 12:
c
0
0
0
0
0
0
0
value: 12
output for x = -12:
f4
ff
ff
ff
ff
ff
ff
ff
value: -4294967308
This seems to have something to do with the way the sign gets stored and converted, because I think Intel (I'm on a Mac) uses 2s-compliment instead of a plain old sign bit. However, I don't really know how to determine if this is true, and if it is, how to compensate for it (preferably in a portable way).
I know that there are a lot of other questions like this, and I've read through them (in fact most of this code is from them), but I still can't get it to work, so I asked my own.
You are right. Intel 64 and IA-32 use 2 complement representation of signed numbers. See Intel 64 and IA-32 Architectures Software Developer’s Manual Section 4.2.1. Reading FFFFFFFFFFFFFFF4 for -12 is therefore correct. In the 2 complement representation negative numbers are represented by taking the corresponding positive, inverting all the bits and adding 1:
12 = 000000000000000C -> FFFFFFFFFFFFFFF3 -> FFFFFFFFFFFFFFF4 = -12
If I can add something, you chould convert your char array to an uint64_t also by doing:
int64_t CharsToInt(uint8_t* chars) {
return *(int64_t*)chars;
}
After messing around with it some more, this is what I finally got working (I think). It actually avoids having to deal with endianness and 2s-compliment all together, by removing the sign and reapplying it after the conversion, using C masks and multiplication:
int64_t CharsToInt(uint8_t* chars) {
// Don't modify argument
uint8_t tmp;
tmp = chars[0];
bool neg = false;
if (tmp & 0x80) {
tmp &= 0x7f;
neg = true;
}
int64_t rv = chars[7] + (chars[6] * 0x100) + (chars[5] * 0x10000) + (chars[4] * 0x1000000) + (chars[3] * 0x100000000) + (chars[2] * 0x10000000000) + (chars[1] * 0x1000000000000) + (tmp * 0x100000000000000);
if (neg) {
rv *= -1;
}
return rv;
}
void IntToChars(int64_t i, uint8_t* chars) {
int64_t num = i;
bool neg = false;
if (i & 0x8000000000000000) {
neg = true;
num *= -1;
}
chars[0] = num / 0x100000000000000;
num = num % 0x100000000000000;
chars[1] = num / 0x1000000000000;
num = num % 0x1000000000000;
chars[2] = num / 0x10000000000;
num = num % 0x10000000000;
chars[3] = num / 0x100000000;
num = num % 0x100000000;
chars[4] = num / 0x1000000;
num = num % 0x1000000;
chars[5] = num / 0x10000;
num = num % 0x10000;
chars[6] = num / 0x100;
num = num % 0x100;
chars[7] = num;
if (neg) {
chars[0] += 0x80;
}
}
I am currently working on a program where I need to have this kind of output:
I have to output the binary in IEEE 754 of 64 and 32-bit numbers in C.
I already have the double and single floating point approximation, but I'm having trouble finding out how to output the binary of these in IEEE 754 notation, and color code them as well. Any thoughts/solutions on how to do this would be much appreciated.
This does not guarantee the correct answer if the underlying machine is something esoteric, however:
float f = 3.14;
uint32_t u;
memcpy(&u, &f, sizeof u);
for (int i = 31; i >= 0; i--)
putchar('0' + ((u >> i) & 1));
I decided to take the opportunity to refresh my memory of the IEE-754 floating-point standard. Below is a mashup I made for displaying a string in its single-precision floating point number representation, though it is easily modified for the double-precision format.
The code won't work with +Inf, -Inf, NaN, trailing-zero, fractionless and leftout-zero (.fraction instead of 0.fraction or integer. instead of integer.0) numbers, it's just supposed to give the general idea of how to do what you want to do in a portable and well-defined (and highly entertaining) way.
#define EXPLEN 8 /* Fraction length for single-precision */
#define SIGNIFLEN 23 /* Significand length for single-precision */
#define EXPBIAS 0x7F /* Exponent bias for single-precision */
#define BITLEN (1 + EXPLEN + SIGNIFLEN)
BOOL strToFloat(char *floatStr, char *outBits, size_t outBitsLen){
unsigned long int floatStrLength = strlen(floatStr), intPart, fracPart, intPartHighestBit = 1, fracPartLength,
fracPartPowTen = 1, temp;
char roundBit, stickyBit, expPart = 0;
int i;
/* Get sign */
if (floatStr[0] == '-'){
floatStr++;
outBits[0] = '1';
} else {
if (floatStr[0] == '+')
floatStr++;
outBits[0] = '0';
}
if (sscanf(floatStr, "%lu.%lu", &intPart, &fracPart) == EOF ||
outBitsLen < BITLEN + 1)
return FALSE; /* Failure */
/* Get integer part */
temp = intPart;
while (temp >>= 1)
intPartHighestBit <<= 1;
for (i = EXPLEN + 1; i < BITLEN && (intPartHighestBit >>= 1); i++, expPart++)
outBits[i] = !!(intPart & intPartHighestBit) + '0';
/* Get fraction part */
fracPartLength = strlen(strchr(floatStr, '.'));
while (--fracPartLength)
fracPartPowTen *= 10;
if (!intPart && i == EXPLEN + 1)
if (fracPart > 0){
i--;
expPart--;
} else
expPart = -EXPBIAS;
for (; i < BITLEN; fracPart = (fracPart << 1) % fracPartPowTen){
outBits[i] = !!((fracPart << 1) - (fracPart << 1) % fracPartPowTen) + '0';
if (outBits[i] == '0' && i == EXPLEN) /* Start writing only after first set bit is reached if number <1 */
expPart--;
else
i++;
}
/* Get exponent part */
for (i = EXPLEN, expPart += EXPBIAS; i > 0; i--, expPart >>= 1)
outBits[i] = (unsigned char)expPart % 2 + '0';
/* Round fraction part (to-nearest mode) */
if ((fracPart << 1) - (fracPart << 1) % fracPartPowTen){ /* Guard bit set, rounding needed */
fracPart = (fracPart << 1) % fracPartPowTen;
roundBit = !!((fracPart << 1) - (fracPart << 1) % fracPartPowTen);
fracPart = (fracPart << 1) % fracPartPowTen;
stickyBit = !!((fracPart << 1) - (fracPart << 1) % fracPartPowTen);
if (roundBit || stickyBit || outBits[BITLEN - 1] == '0'){ /* Round up, add 1 to mantissa (and to exponent
if mantissa overflows)*/
for (i = BITLEN - 1; outBits[i] == '1' && i > 0; i--)
outBits[i] = '0';
outBits[i] = '1';
}
}
outBits[BITLEN] = '\0';
return TRUE; /* Success */
}
Example usage:
char *str = "-3.14",
*outFloat = malloc(BITLEN + 1);
if (outFloat && strToFloat(str, outFloat, BITLEN + 1))
printf("%s", outFloat);
outputs
11000000010010001111010111000011
UPDATE: did my best to
remove magic numbers so it's easier to change this to use the double-precision format;
fix (I think) the rounding overflows;
fix zeroes issues;
refactor the code for setting the sign bit; and I also fiddled with some types, both per #Segmented's request in the comments.
Well, that was lots of fun! If you see any errors or space for improvement in this (rather hasty) code, please post it!
I'm to stupid right now to solve this problem...
I get a BCD number (every digit is an own 4Bit representation)
For example, what I want:
Input: 202 (hex) == 514 (dec)
Output: BCD 0x415
Input: 0x202
Bit-representation: 0010 0000 0010 = 514
What have I tried:
unsigned int uiValue = 0x202;
unsigned int uiResult = 0;
unsigned int uiMultiplier = 1;
unsigned int uiDigit = 0;
// get the dec bcd value
while ( uiValue > 0 )
{
uiDigit= uiValue & 0x0F;
uiValue >>= 4;
uiResult += uiMultiplier * uiDigit;
uiMultiplier *= 10;
}
But I know that's very wrong this would be 202 in Bit representation and then split into 5 nibbles and then represented as decimal number again
I can solve the problem on paper but I just cant get it in a simple C-Code
You got it the wrong way round. Your code is converting from BCD to binary, just as your question's (original) title says. But the input and output values you provided are correct only if you convert from binary to BCD. In that case, try:
#include <stdio.h>
int main(void) {
int binaryInput = 0x202;
int bcdResult = 0;
int shift = 0;
printf("Binary: 0x%x (dec: %d)\n", binaryInput , binaryInput );
while (binaryInput > 0) {
bcdResult |= (binaryInput % 10) << (shift++ << 2);
binaryInput /= 10;
}
printf("BCD: 0x%x (dec: %d)\n", bcdResult , bcdResult );
return 0;
}
Proof: http://ideone.com/R0reQh
Try the following.
unsigned long toPackedBcd (unsigned int val)
{
unsigned long bcdresult = 0; char i;
for (i = 0; val; i++)
{
((char*)&bcdresult)[i / 2] |= i & 1 ? (val % 10) << 4 : (val % 10) & 0xf;
val /= 10;
}
return bcdresult;
}
Also one may try the following variant (although maybe little inefficient)
/*
Copyright (c) 2016 enthusiasticgeek<enthusiasticgeek#gmail.com> Binary to Packed BCD
This code may be used (including commercial products) without warranties of any kind (use at your own risk)
as long as this copyright notice is retained.
Author, under no circumstances, shall not be responsible for any code crashes or bugs.
Exception to copyright code: 'reverse string function' which is taken from http://stackoverflow.com/questions/19853014/reversing-a-string-in-place-in-c-pointers#19853059
Double Dabble Algorithm for unsigned int explanation
255(binary) - base 10 -> 597(packed BCD) - base 16
H| T| U| (Keep shifting left)
11111111
1 1111111
11 111111
111 11111
1010 11111 <-----added 3 in unit's place (7+3 = 10)
1 0101 1111
1 1000 1111 <-----added 3 in unit's place (5+3 = 8)
11 0001 111
110 0011 11
1001 0011 11 <-----added 3 in ten's place (6+3 = 9)
1 0010 0111 1
1 0010 1010 1 <-----added 3 in unit's place (7+3 = 10)
10 0101 0101 -> binary 597 but bcd 255
^ ^ ^
| | |
2 5 5
*/
#include <stdio.h>
#include <string.h>
//Function Prototypes
unsigned int binaryToPackedBCD (unsigned int binary);
char * printPackedBCD(unsigned int bcd, char * bcd_string);
// For the following function see http://stackoverflow.com/questions/19853014/reversing-a-string-in-place-in-c-pointers#19853059
void reverse(char *str);
//Function Definitions
unsigned int binaryToPackedBCD (unsigned int binary) {
const unsigned int TOTAL_BITS = 32;
/*Place holder for bcd*/
unsigned int bcd = 0;
/*counters*/
unsigned int i,j = 0;
for (i=0; i<TOTAL_BITS; i++) {
/*
Identify the bit to append to LSB of 8 byte or 32 bit word -
First bitwise AND mask with 1.
Then shift to appropriate (nth shift) place.
Then shift the result back to the lsb position.
*/
unsigned int binary_bit_to_lsb = (1<<(TOTAL_BITS-1-i)&binary)>>(TOTAL_BITS-1-i);
/*shift by 1 place and append bit to lsb*/
bcd = ( bcd<<1 ) | binary_bit_to_lsb;
/*printf("=> %u\n",bcd);*/
/*Don't add 3 for last bit shift i.e. in this case 32nd bit*/
if( i >= TOTAL_BITS-1) {
break;
}
/*else continue*/
/* Now, check every nibble from LSB to MSB and if greater than or equal 5 - add 3 if so */
for (j=0; j<TOTAL_BITS; j+=4) {
unsigned int temp = (bcd & (0xf<<j))>>j;
if(temp >= 0x5) {
/*printf("[%u,%u], %u, bcd = %u\n",i,j, temp, bcd);*/
/*Now, add 3 at the appropriate nibble*/
bcd = bcd + (3<<j);
// printf("Now bcd = %u\n", bcd);
}
}
}
/*printf("The number is %u\n",bcd);*/
return bcd;
}
char * printPackedBCD(unsigned int bcd, char * bcd_string) {
const unsigned int TOTAL_BITS = 32;
printf("[LSB] =>\n");
/* Now, check every nibble from LSB to MSB and convert to char* */
for (unsigned int j=0; j<TOTAL_BITS; j+=4) {
//for (unsigned int j=TOTAL_BITS-1; j>=4; j-=4) {
unsigned int temp = (bcd & (0xf<<j))>>j;
if(temp==0){
bcd_string[j/4] = '0';
} else if(temp==1){
bcd_string[j/4] = '1';
} else if(temp==2){
bcd_string[j/4] = '2';
} else if(temp==3){
bcd_string[j/4] = '3';
} else if(temp==4){
bcd_string[j/4] = '4';
} else if(temp==5){
bcd_string[j/4] = '5';
} else if(temp==6){
bcd_string[j/4] = '6';
} else if(temp==7){
bcd_string[j/4] = '7';
} else if(temp==8){
bcd_string[j/4] = '8';
} else if(temp==9){
bcd_string[j/4] = '9';
} else {
bcd_string[j/4] = 'X';
}
printf ("[%u - nibble] => %c\n", j/4, bcd_string[j/4]);
}
printf("<= [MSB]\n");
reverse(bcd_string);
return bcd_string;
}
// For the following function see http://stackoverflow.com/questions/19853014/reversing-a-string-in-place-in-c-pointers#19853059
void reverse(char *str)
{
if (str != 0 && *str != '\0') // Non-null pointer; non-empty string
{
char *end = str + strlen(str) - 1;
while (str < end)
{
char tmp = *str;
*str++ = *end;
*end-- = tmp;
}
}
}
int main(int argc, char * argv[])
{
unsigned int number = 255;
unsigned int bcd = binaryToPackedBCD(number);
char bcd_string[8];
printPackedBCD(bcd, bcd_string);
printf("Binary (Base 10) = %u => Packed BCD (Base 16) = %u\n OR \nPacked BCD String = %s\n", number, bcd, bcd_string);
return 0;
}
The real problem here is confusion of bases and units
The 202 should be HEX which equates to 514 decimal... and therefore the BCD calcs are correct
Binary code decimal will convert the decimal (514) into three nibble sized fields:
- 5 = 0101
- 1 = 0001
- 4 = 0100
The bigger problem was that you have the title the wrong way around, and you are converting Uint to BCD, whereas the title asked for BCD to Unint
My 2 cents, I needed similar for a RTC chip which used BCD to encode the time and date info. Came up with the following macros that worked fine for the requirement:
#define MACRO_BCD_TO_HEX(x) ((BYTE) ((((x >> 4) & 0x0F) * 10) + (x & 0x0F)))
#define MACRO_HEX_TO_BCD(x) ((BYTE) (((x / 10 ) << 4) | ((x % 10))))
A naive but simple solution:
char buffer[16];
sprintf(buffer, "%d", var);
sscanf(buffer, "%x", &var);
This is the solution that I developed and works great for embedded systems, like Microchip PIC microcontrollers:
#include <stdio.h>
void main(){
unsigned int output = 0;
unsigned int input;
signed char a;
//enter any number from 0 to 9999 here:
input = 1265;
for(a = 13; a >= 0; a--){
if((output & 0xF) >= 5)
output += 3;
if(((output & 0xF0) >> 4) >= 5)
output += (3 << 4);
if(((output & 0xF00) >> 8) >= 5)
output += (3 << 8);
output = (output << 1) | ((input >> a) & 1);
}
printf("Input decimal or binary: %d\nOutput BCD: %X\nOutput decimal: %u\n", input, output, output);
}
This is my version for a n byte conversion:
//----------------------------------------------
// This function converts n bytes Binary (up to 8, but can be any size)
// value to n bytes BCD value or more.
//----------------------------------------------
void bin2bcdn(void * val, unsigned int8 cnt)
{
unsigned int8 sz, y, buff[20]; // buff = malloc((cnt+1)*2);
if(cnt > 8) sz = 64; // 8x8
else sz = cnt * 8 ; // Size in bits of the data we shift
memset(&buff , 0, sizeof(buff)); // Clears buffer
memcpy(&buff, val, cnt); // Copy the data to buffer
while(sz && !(buff[cnt-1] & 0x80)) // Do not waste time with null bytes,
{ // so search for first significative bit
rotate_left(&buff, sizeof(buff)); // Rotate until we find some data
sz--; // Done this one
}
while(sz--) // Anyting left?
{
for( y = 0; y < cnt+2; y++) // Here we fix the nibbles
{
if(((buff[cnt+y] + 0x03) & 0x08) != 0) buff[cnt+y] += 0x03;
if(((buff[cnt+y] + 0x30) & 0x80) != 0) buff[cnt+y] += 0x30;
}
rotate_left(&buff, sizeof(buff)); // Rotate the stuff
}
memcpy(val, &buff[cnt], cnt); // Copy the buffer to the data
// free(buff); //in case used malloc
} // :D Done
long bin2BCD(long binary) { // double dabble: 8 decimal digits in 32 bits BCD
if (!binary) return 0;
long bit = 0x4000000; // 99999999 max binary
while (!(binary & bit)) bit >>= 1; // skip to MSB
long bcd = 0;
long carry = 0;
while (1) {
bcd <<= 1;
bcd += carry; // carry 6s to next BCD digits (10 + 6 = 0x10 = LSB of next BCD digit)
if (bit & binary) bcd |= 1;
if (!(bit >>= 1)) return bcd;
carry = ((bcd + 0x33333333) & 0x88888888) >> 1; // carrys: 8s -> 4s
carry += carry >> 1; // carrys 6s
}
}
Simple solution
#include <stdio.h>
int main(void) {
int binaryInput = 514 ; //0x202
int bcdResult = 0;
int digit = 0;
int i=1;
printf("Binary: 0x%x (dec: %d)\n", binaryInput , binaryInput );
while (binaryInput > 0) {
digit = binaryInput %10; //pick digit
bcdResult = bcdResult+digit*i;
i=16*i;
binaryInput = binaryInput/ 10;
}
printf("BCD: 0x%x (dec: %d)\n", bcdResult , bcdResult );
return 0;
}
Binary: 0x202 (dec: 514)
BCD: 0x514 (dec: 1300)
You can also try the following:
In every iteration the remainder ( represented as a nibble ) is positioned in its corresponding place.
uint32_t bcd_converter(int num)
{
uint32_t temp=0;
int i=0;
while(num>0){
temp|=((num%10)<<i);
i+=4;
num/=10;
}
return temp;
}