Is this C function written in poor form? - c

char byte_to_ascii(char value_to_convert, volatile char *converted_value) {
if (value_to_convert < 10) {
return (value_to_convert + 48);
} else {
char a = value_to_convert / 10;
double x = fmod((double)value_to_convert, 10.0);
char b = (char)x;
a = a + 48;
b = b + 48;
*converted_value = a;
*(converted_value+1) = b;
return 0;
}
}
The purpose of this function is to take an unsigned char value of 0 through 99 and return either it's ascii equivalent in the case it is 0-9 or manipulate a small global character array that can be referenced from the calling code following function completion.
I ask this question because two compilers from the same vendor interpret this code in different ways.
This code was written as a way to parse address bytes sent via RS485 into strings that can easily be passed to a send-lcd-string function.
This code is written for the PIC18 architecture (8 bit uC).
The problem is that the free/evaluation version of a particular compiler generates perfect assembly code that works while suffering a performance hit, but the paid and supposedly superior compiler generates code more efficiently at the expense of being able reference the addresses of all my byte arrays used to drive the graphics on my lcd display.
I know I'm putting lots of mud in the water by using a proprietary compiler for a less than typical architecture, but I hope someone out there has some suggestions.
Thanks.

I would definitely avoid using floating point anything on a PIC. And I would -try not to- use any divisions. How many times do you see sending a non-ascii char to the LCD? Can you save it to the LCD's memory and then call it by it's memory position?
Here's what a divide by 10 looks like in my code, note the 17 cycles it needs to complete. Think about how long that will take, and make sure there is nothing else waiting on this.
61: q = d2 / 10;
01520 90482E mov.b [0x001c+10],0x0000
01522 FB8000 ze 0x0000,0x0000
01524 2000A2 mov.w #0xa,0x0004
01526 090011 repeat #17
01528 D88002 div.uw 0x0000,0x0004
0152A 984F00 mov.b 0x0000,[0x001c+8]
If you do a floating point anything in your code, look in the program memory after you've compiled it, on the Symbolic tab (so you can actually read it) and look for the floating point code that will need to be included. You'll find it up near the top (depending on your code), soon(ish) after the _reset label.
Mine starts at line number 223 and memory address of 001BC with _ floatsisf, continues through several additional labels (_fpack, _divsf3, etc) and ends in _funpack, last line at 535 and memory address 0042C. If you can handle (42C-1BC = 0x270 =) 624 bytes of lost program space, great, but some chips have just 2k of space and that's not an option.
Instead of floating point, if it's possible, try to use fixed point arithmetic, in base 2.
As far as not being able to reference all the byte arrays in your LCD, have you checked to make sure that you're not trying to send a null (which is a fine address) but it get's stopped by code checking for the end of an ascii string? (it's happened to me before).

modulo and integer division can be very very expensive. I have do not know about your particular architecture, but my guess it is expensive there as well.
If you need both, division and modulo, do one of them and get the other one by multiplication/difference.
q =p/10;
r = p - q*10;

I'd probably write that as:
char byte_to_ascii(char value_to_convert, volatile char *converted_value)
{
if (value_to_convert < 10) {
return value_to_convert + '0';
} else {
converted_value[0] = (value_to_convert / 10) + '0';
converted_value[1] = (value_to_convert % 10) + '0';
return 0;
}
}

Is it poor form to convert to floating, call fmod, and convert to integer, instead of just using the % operator? I would say yes. There are more readable ways to slow down a program to meet some timing requirement, for example sleeping in a for loop. No matter what compiler or what tweaking of assembly code or whatever else, this is a highly obfuscated way to control the execution speed of your program, and I call it poor form.
If perfect assembly code means that it works right but it's even slower than the conversions to floating point and back, then use integers and sleep in a for loop.
As for the imperfect assembly code, what's the problem? "at the expense of being able reference the addresses of all my byte arrays"? It looks like type char* is working in your code, so it seems that you can address all your byte arrays the way the C standard says you can. What's the problem?

Frankly, I would say yes..
If you wanted b to be the remainder, either use MOD or roll-your-own:
char a = value_to_convert / 10;
char b = value_to_convert - (10 * a);
Conversion to/from floats is never the way to do things, unless your values really are floats.
Furthermore, I would strongly recommend to stick to the convention of explicitly referring to your datatypes as 'signed' or 'unsigned', and leave the bare 'char' for when it actually is a character (part of a string). You are passing in raw data, which I feel should be an unsigned char (assuming of course, that the source is unsigned!). It is easy to forget if something should be signed/unsigned, and with a bare char, you'll get all sorts of roll-over errors.
Most 8-bit micros take forever for a multiply (and more than forever for a divide), so try and minimise these.
Hope this helps..

The code seems to be doing two very different things, depending on whether it's given a number in the range 0-9 or 10-99. For that reason, I would say that this function is written in poor form: I would split your function into two functions.

Since we're discussing divisions by 10 here..
This is my take. It only simple operations and does not even need wide registers.
unsigned char divide_by_10 (unsigned char value)
{
unsigned char q;
q = (value>>1) + (value>>2);
q += (q>>4);
q >>= 3;
value -= (q<<3)+q+q;
return q+((value+6)>>4);
}
Cheers,
Nils

It is typical for optimizers to do unwanted thingies from time to time if you poke around in the internals.
Is your converted_value a global value or otherwise assigned in such a fashion that the compiler knows not to touch it?

PIC's don't like doing pointer arithmetic.
As Windows programmer points out, use the mod operator (see below.)
char byte_to_ascii(char value_to_convert, volatile char *converted_value) {
if (value_to_convert < 10) {
return (value_to_convert + 48);
} else {
char a = value_to_convert / 10;
char b = value_TO_convert%10;
a = a + 48;
b = b + 48;
*converted_value = a;
*(converted_value+1) = b;
return 0;
}
}

Yes, I believe that your function:
char byte_to_ascii(char value_to_convert, volatile char *converted_value) {
if (value_to_convert < 10) {
return (value_to_convert + 48);
} else {
char a = value_to_convert / 10;
double x = fmod((double)value_to_convert, 10.0);
char b = (char)x;
a = a + 48;
b = b + 48;
*converted_value = a;
*(converted_value+1) = b;
return 0;
}
}
is in poor form:
Don't use decimal numbers for ASCII chars, use the character, i.e. '#' instead of 0x40.
There is no need for using the fmode function.
Here is my example:
// Assuming 8-bit octet
char value;
char largeValue;
value = value_to_convert / 100;
value += '0';
converted_value[0] = value;
largeValue = value_to_convert - value * 100;
value = largeValue / 10;
value += '0';
converted_value[1] = value;
largeValue = largeValue - value * 10;
value += '0';
converted_value[2] = value;
converted_value[3] = '\0'; // Null terminator.
Since there are only 3 digits, I decided to unroll the loop. There are no branches to interrupt the prefetching of instructions. No floating point exceptions, just integer arithmetic.
If you leading spaces instead of zeros, you can try this:
value = (value == 0) ? ' ' : value + '0';

Just to be a nitwitt, but multiple return statements from the same function can be considered bad form (MISRA).
Also, some of the discussions above are on the limit of permature optimizations. Some tasks must be left to the compiler. However, in such a minimalistic embedded environment, these tricks may be valid still.

Related

Looking at and using individual bytes in void pointers in C [duplicate]

This question already has answers here:
What does void* mean and how to use it?
(10 answers)
Closed 5 years ago.
I'm trying to make a calculator that takes a void pointer called yourVal, look at the first byte and decide if it's a '*' or '/'. Based on the sign, i multiply bytes 3+4, 5+6, and 7+8. say i have *1234567. I multiply 23 * 45 * 67. With the division, I divide byte 5(45) by byte 3(23). I'm a novice with pointers in C, and I really have no idea how to even set a value to a void pointer. When I do the following in main
void *yourVal;
*yourVal = "*1234567";
printf("%s\n", yourVal);
I'm not able to dereference a void pointer. But I tried with a char pointer, and I have the same issue.
This is my code for the calculator function. Based on whether I use printf or not, I get different results.
int calculator(void *yourVal){
char *byteOne;
short int *byteThree, *byteFive, *byteSeven;
int value;
byteOne = (char *)yourVal;
byteThree = (short int *)yourVal+2;
byteFive = (short int *)yourVal+4;
byteSeven= (short int *)yourVal+6;
if(*byteOne == '*') {
value = *byteThree * *byteFive * *byteSeven;
printf("You multiplied\n");
}
else if(*byteOne == '/') {
if (*byteThree == 0) {
value = 0xBAD;
printf("Your input is invalid\n");
}
else {
value = *byteFive / *byteThree;
printf("You divided\n");
}
}
else {
value = 0xBAD;
printf("Your input is invalid\n");
}
}
The division isn't working at all, and the multiplication only grabs one digit. Any tips would be appreciated. I looked at various sources but I'm not seeing how to work with void pointers efficiently. Also, I can't use any library functions other than printf, and this is a school assignment, so try not to give too many spoilers or do it for me. We were given one hint, which is to cast yourVal to a structure. But I'm lost on that. Thanks
byteOne = (char *)payload;
byteThree = (short int *)yourVal+2;
byteFive = (short int *)yourVal+4;
byteSeven= (short int *)yourVal+6;
This doesn't do what you think it does. If you want to read the numbers at these positions, you need to do something like.
char* Value = yourValue;
unsigned byteOne, byteThree, byteFive, byteSeven;
byteOne = Value[0] - '0';
byteThree = Value[2] - '0';
byteFive = Value[4] - '0';
byteSeven = Value[6] - '0';
What I have done here is read the byte at that position and subtract the ASCII value of '0' to get the numerical value of that character. But again this will work only for a single character.
If you need to read more characters you will have to use library functions like sscanf or atoi.
The void pointer adds no functionality you need to solve this problem, it just complicates things. Use a char pointer instead.
"*1234567" is a string, not an array of integers. You cannot treat it as an array of integers. Each character would have to be converted to an integer before you do arithmetic. The easiest way to do that is to subtract by the ASCII character '0'.
"...i multiply bytes 3+4..." When counting bytes, you always start at 0. In the string "*1234567", the 2 is the byte with index 2 not 3.
"Based on the sign, i multiply bytes 3+4, 5+6, and 7+8. say i have *1234567. I multiply 23 * 45 * 67. With the division, I divide byte 5(45) by byte 3(23)"
I fail to see how this algorithm makes any sense. What is the 1 there for? Why aren't you using some conventional formatting such as prefix, postfix or just plainly typed-out equations?
Example:
int calculator (const char* yourVal)
...
int byte2 = yourVal[2] - '0';

How to print really large numbers within a tribonacci sequence [closed]

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 5 years ago.
Improve this question
So i recently did a university exam and one of the questions asked us to create a program that would print out the nth number in the tribonacci sequence (1,1,1,3,5,9,17,31...). These numbers were said to go as large as 1500 digits long. I created a recursive function that worked for the first 37 tribonacci numbers. But a stack overflow occurred at the 38th number. The question had warned us about this and said that we would somehow need to overcome this, but i have no idea how. Were we meant to create our own data type?
double tribonacci(int n){
if(n < 4){
return 1;
}else{
return tribonacci(n-3) + tribonacci(n-2) + tribonacci(n-1);
}
}
int main(int argc, char *argv[]){
double value = tribonacci(atoi(argv[1]));
printf("%lf\n", value);
}
This is the solution i wrote under exam conditions, which was within 15 minutes.
The program took the value of n from an input in the command line. We were not allowed to use any libraries except for stdlib.h and stdio.h. So with all that said, how might one create a data type large enough to print out numbers with 1500 digits (since the double data type only holds enough for up until the 37th tribonacci number)? Or is there another method to this question?
You should use some arbitrary-precision arithmetic library (a.k.a. Bigints or bignums) if your teacher allows them. I recommend GMPlib, but there are others.
See also this answer (notably if your teacher wants you to write some crude arbitrary precision addition).
For a development time limited exam solution, I'd definitely go for the quick & dirty approach, but I wouldn't exactly complete it within 15 minutes.
The problem size is restricted to 1500 characters, computing tribonacci indicates that you will always need to carry subresult N-3, N-2 and N-1 in order to compute subresult N. So lets define a suitable static data structure with the right starting values (its 1;1;1 in your question, but I think it should be 0;1;1):
char characterLines[4][1501] = { { '0', 0 }, { '1', 0 }, { '1', 0 } };
Then define an add function that operates on character arrays, expecting '\0' as end of array and the character numbers '0' to '9' as digits in a way that the least significant digit comes first.
void addBigIntegerCharacters(const char* i1, const char* i2, char* outArray)
{
int carry = 0;
while(*i1 && *i2)
{
int partResult = carry + (*i1 - '0') + (*i2 - '0');
carry = partResult / 10;
*outArray = (partResult % 10) + '0';
++i1; ++i2; ++outArray;
}
while(*i1)
{
int partResult = carry + (*i1 - '0');
carry = partResult / 10;
*outArray = (partResult % 10) + '0';
++i1; ++outArray;
}
while(*i2)
{
int partResult = carry + (*i2 - '0');
carry = partResult / 10;
*outArray = (partResult % 10) + '0';
++i2; ++outArray;
}
if (carry > 0)
{
*outArray = carry + '0';
++outArray;
}
*outArray = 0;
}
Compute the tribonacci with the necessary number of additions:
// n as 1-based tribonacci index.
char* computeTribonacci(int n)
{
// initialize at index - 1 since it will be updated before first computation
int srcIndex1 = -1;
int srcIndex2 = 0;
int srcIndex3 = 1;
int targetIndex = 2;
if (n < 4)
{
return characterLines[n - 1];
}
n -= 3;
while (n > 0)
{
// update source and target indices
srcIndex1 = (srcIndex1 + 1) % 4;
srcIndex2 = (srcIndex2 + 1) % 4;
srcIndex3 = (srcIndex3 + 1) % 4;
targetIndex = (targetIndex + 1) % 4;
addBigIntegerCharacters(characterLines[srcIndex1], characterLines[srcIndex2], characterLines[targetIndex]);
addBigIntegerCharacters(characterLines[targetIndex], characterLines[srcIndex3], characterLines[targetIndex]);
--n;
}
return characterLines[targetIndex];
}
And remember that your least significant digit comes first when printing the result
void printReverse(const char* start)
{
const char* printIterator = start;
while (*printIterator)
{
++printIterator;
}
do
{
putchar(*(--printIterator));
} while (printIterator != start);
}
int main()
{
char* c = computeTribonacci(50); // the real result is the array right-to-left
printReverse(c);
}
As said, this is kindof quick & dirty coded, but still not within 15 minutes.
The reason why I use a separate char per decimal digit is mainly readability and conformity to the way how decimal math works on pen&paper, which is an important factor when development time is limited. With focus on runtime constraints rather than development time, I'd probably group the numbers in an array of unsigned long long, each representing 18 decimal digits. I would still focus on decimal digit groupings, because this is a lot easier to print as characters using the standard library functions. 18 because I need one digit for math overflow and 19 is the limit of fully available decimal digits for unsigned long long. This would result in a few more changes... 0 couldn't be used as termination character anymore, so it would probably be worth saving the valid length of each array. The principle of add and computeTribonacci would stay the same with some minor technical changes, printing would need some tweaks to ensure a length 18 output for each group of numbers other than the most significant one.
You require a different algorithm. The code posted cannot suffer from an integer overflow, as it does all its calculations in doubles. So you are probably getting a stack overflow instead. The posted code uses exponential time and space, and at N=38 that exponential space is probably overflowing the stack. Some alternatives, in increasing order of efficiency and complexity:
Use the "memoization" technique to optimize the algorithm you have.
Build up the answer starting by calculating N=4, and iterating upwards. No recursion is then needed.
Do the mathematics (or find someone who can) to get the "closed form solution" that allows direct calculation of the answer. See https://en.wikipedia.org/wiki/Fibonacci_number#Closed-form_expression for how this works for regular fibonacci numbers.
You will also need a "big number" data structure - see other answers.
You need to replace the + operation with an operator ADD made by yourself and encode BigIntegers as you wish -- there are lots of ways to encode BigIntegers.
So you need to define yourself a datatype BigInteger and the following operations
ADD : BigInteger, BigInteger -> BigInteger
1+ : BigInteger -> BigInteger
2- : BigInteger -> BigInteger
<4 : BigInteger -> boolean
The constants 1,2,4 as BigInteger
and after having replaced these things write a standard function to compute fibb in linear time and space.

C error: pointer expected

I made a simple program in C that finds if a number is prime. I am new to C and decided to try to use scanf instead of hardcoded numbers to check. When I run my code:
#include <stdio.h>
typedef int bool;
#define true 1
#define false 0
int main(){
//I am going to check if the "checking" variable is a prime
int checking;
scanf("%d",checking);
//"stopper" is where the for loop will stop
int stopper = checking**0.5 + 1;
//"found" will show if I have found something bad
bool found = false;
for (int i = 2; i < stopper; i++)
{
if (checking % i == 0){found = true; break;}
}
if (!found) {printf("it is prime");}
else {printf("it is not prime");}
}
when I try to compile this with TCC it gives the error (primes.c is the name of the document)
primes.c:12 error: pointer expected
I don't know how to fix this.
EDIT: I just made stopper = checking/2 and the program crashes
int stopper = checking**0.5 + 1;
line 12... what do you expect the ** operator to do?
A * typically performs a multiply, or dereferences a pointer.
The compiler could be interpreting it as follows:
int stopper = checking * (*0.5) + 1;
Of course, trying to dereference a float (*0.5) is bad / impossible, hence the error.
Did you mean:
instead of **, you meant * (multiply)
instead of ** (not a C operator), you meant pow() (raise to the power of)
You also need to be specific - even if you're an expert at precedance, the reader may not be, and you may well be wrong.
If you're not sure what's going on, use braces to be specific, which of the following do you mean?
int stopper = checking * (0.5 + 1);
int stopper = (checking * 0.5) + 1;
int stopper = pow(checking, 0.5) + 1;
int stopper = pow(checking, 0.5 + 1);
If you are indeed after the square root, then as #JeremyP says, invert your thinking - multiply is much less costly than pow():
for (int i = 2; i * i <= checking; i++)
You have two problems in your program:
(1) Replace
int stopper = checking**0.5 + 1;
with
int stopper = checking*0.5 + 1;
(2) Replace
scanf("%d",checking);
with
scanf("%d",&checking);
You should be good to after these corrections.
There's no built in operator to raise a number to the power of another number. There is a function to do that - also a square root function but you don't need them (see below).
x**y
is parsed as
x* (*y)
which is where your pointer error comes from
Instead of trying to find the square root, come at it from the other direction, change your for loop like this
for (int i = 2; i * i <= checking; i++)
Also, as others have said, the scanf is wrong.
scanf("%d",&checking);
// ^- scanf needs a pointer to an int.
Firstly, the scanf is wrong.
Use scanf("%d",&checking);
For finding the square root use math.h library for sqrt function.
int stopper = sqrt(checking) + 1;
There were a lot of typing mistakes in your code. Please, correct your syntax before asking a question.
Ideone link for code

Convert read-only character array to float without null termination in C

I'm looking for a C function like the following that parses a length-terminated char array that expresses a floating point value and returns that value as a float.
float convert_carray_to_float( char const * inchars, int incharslen ) {
...
}
Constraints:
The character at inchars[incharslen] might be a digit or other character that might confuse the commonly used standard conversion routines.
The routine is not allowed to invoke inchars[incharslen] = 0 to create a z terminated string in place and then use the typical library routines. Even patching up the z-overwritten character before returning is not allowed.
Obviously one could copy the char array in to a new writable char array and append a null at the end, but I am hoping to avoid copying. My concern here is performance.
This will be called often so I'd like this to be as efficient as possible. I'd be happy to write my own routine that parses and builds up the float, but if that's the best solution, I'd be interested in the most efficient way to do this in C.
If you think removing constraint 3 really is the way to go to achieve high performance, please explain why and provide a sample that you think will perform better than solutions that maintain constraint 3.
David Gay's implementation, used in the *BSD libcs, can be found here: https://svnweb.freebsd.org/base/head/contrib/gdtoa/ The most important file is strtod.c, but it requires some of the headers and utilities. Modifying that to check the termination every time the string pointer is updated would be a bit of work but not awful.
However, you might afterwards think that the cost of the extra checks is comparable to the cost of copying the string to a temporary buffer of known length, particularly if the strings are short and of a known length, as in your example of a buffer packed with 3-byte undelimited numbers. On most architectures, if the numbers are no more than 8 bytes long and you were careful to ensure that the buffer had a bit of tail room, you could do the copy with a single 8-byte unaligned memory access at very little cost.
Here's a pretty good outline.
Not sure it covers all cases, but it shows most of the flow:
float convert_carray_to_float(char const * inchars, int incharslen)
{
int Sign = +1;
int IntegerPart = 0;
int DecimalPart = 0;
int Denominator = 1;
bool beforeDecimal = true;
if (incharslen == 0)
{
return 0.0f;
}
int i=0;
if (inchars[0] == '-')
{
Sign = -1;
i++;
}
if (inchars[0] == '+')
{
Sign = +1;
i++;
}
for( ; i<incharslen; ++i)
{
if (inchars[i] == '.')
{
beforeDecimal = false;
continue;
}
if (!isdigit(inchars[i]))
{
return 0.0f;
}
if (beforeDecimal)
{
IntegerPart = 10 * IntegerPart + (inchars[i] - '0');
}
else
{
DecimalPart = 10 * DecimalPart + (inchars[i] - '0');
Denominator *= 10;
}
}
return Sign * (IntegerPart + ((float)DecimalPart / Denominator));
}

Random number in C

I'm writing my own method to generate a random number with C as follows:
int randomNumber(){
int catch = *pCOUNTER;
int temp = catch;
temp /= 10;
temp *= 10;
return (catch - temp);
}
pCounter is basically a pointer to a register in the device I'm using. The number in that register is always increasing so my idea is to take the first digit only.
At some point, the number returned becomes larger than 9 and I'm not sure if the problem is in my code or the device itself. The device is an Altera DE1 board.
Can anyone please help with that?
Thanks!
Did you declare pCounter as volatile?
volatile unsigned *pCounter = (unsigned *)0xBADDECAF;
int randomNumber(){
return *pCounter % 10;
}
To achieve what you're trying to do in your code:
int catch = *pCOUNTER;
return (catch % 10); // Returns only the ones digit
However, I question if this approach is anywhere close to being reasonably random...
Are you sure you're not looking to use %= instead of /= & *=?
I suspect that your problem might be an 'optimization' introduced by the compiler - if you don't have pCOUNTER declared with the correct volatility, the compiler could be reading through the pointer more than once. I have no idea how many registers your processor might have - if there's not enough to hold catch in a register, it might read it multiple times (once to get something to do the temp calculations on, and again for the final return value).
Try the following, which should ensure that the pCOUNTER device/register is read exactly once:
int randomNumber(){
int catch = *(int volatile*)pCOUNTER;
int temp = catch;
temp /= 10;
temp *= 10;
return (catch - temp);
}
If you're looking for a random digit (0-9 only), try this modification of your method.
int randomNumber(){
return ((*pCOUNTER) % 10);
}
This isn't very random, though. If it's always increasing, presumably at a known rate then it's 100% predictable, not random at all.
Is the rand() function not allowed on that Altera board?
Edit:
You could always write your own PRNG. I did a Google search for "simple random number generator code", and found several simple examples. The simplest ones are along these lines:
int randomNumber()
{
static long a = SomeSeedValue;
a = (a * SomeNumber + AnotherNumber) % SomeLargePrimeNumber;
return a % 65536;
}
If you want to arbitrarily limit the result to 9:
return (catch - temp)%10;
I recommend using a macro constant to abstract the '10' though, otherwise it's a magic number.

Resources