calculating variable issue - Page 1
Forum section: electronics / general

author: Simon
author_rank: Unknown
timestamp: August 21, 2018, 01:24:39 pm
content: I need to do something like:uint16_t speed_2_digital = (uint16_t)(1000000U/(((SPEED_2_RPM*3)/60)));SPEED_2_RPM = 47'000.I do not get the desired result with or without the type casting. Am I exceeding some limit? I get the same result be it a variable or using a macro and regardless of the typecast, or do I need to typecast it high in order to do the math that then goes into a 16 bit variable?

author: Simon
author_rank: Unknown
timestamp: August 21, 2018, 01:25:42 pm
content: 20'000 works but produces a round 1000, 47'000 does not but it is not a rannd number

author: dmills
author_rank: Super Contributor
timestamp: August 21, 2018, 01:51:31 pm
content: 47000 * 3 = 141000, what is INT_MAX (from <limits.h> on your platform?).What type is SPEED_2_RPM?I would note that (((SPEED_2_RPM*3)/60)) is pretty much equivalent to (SPEED_2_RPM / 20) reducing the integer range required.Also that 1000000 can be multiplied by the 20 to give youuint16_t speed_2_digital = 20000000UL/SPEED_2_RPM;Regards, Dan.

author: mikerj
author_rank: Super Contributor
timestamp: August 21, 2018, 01:56:47 pm
content: Quote from: Simon on August 21, 2018, 01:24:39 pmNot enough information, is SPEED_2_RPM a #defined literal? If so you need to show this.Assuming :1) #define SPEED_2_RPM 470002) You are using a platform with 16 bit integersThen (SPEED_2_RPM*3) will immediately overflow a 16 bit integer. To fix this you need to tell the compiler you want to treat the literal (or the multiplier) as a 32 bit value e.g.#define SPEED_2_RPM 47000UL

author: ataradov
author_rank: Super Contributor
timestamp: August 21, 2018, 05:04:46 pm
content: If it is still AVR, then int is 16-bits and you need to watch out for integer overflows.Something like this should work better: "uint16_t speed_2_digital = (uint16_t)(1000000U/((((uint32_t)SPEED_2_RPM*3)/60)));"Although depending on what you are doing, you ma be better off rearranging things in this formula (specifically turn /60 to *60 in the numerator).

author: Simon
author_rank: Unknown
timestamp: August 21, 2018, 05:27:40 pm
content: Quote from: ataradov on August 21, 2018, 05:04:46 pmNope.I was originally trying to do this as a macro but wondered if i needed to forcibly typecast it in a variable assignment. So I simply need to define a number as UL to break out of the 16 bit limit. Yes the speed was going to be a #define.I carried out multiplications first to try and avoid too much discard in dividing.

author: ataradov
author_rank: Super Contributor
timestamp: August 21, 2018, 05:38:06 pm
content: What is the actual result you get. Because for 20000, the correct result is 1000. So I'm not sure why you have "but" in the second post.

author: Simon
author_rank: Unknown
timestamp: August 21, 2018, 05:42:36 pm
content: 20'000 works, 47'000 does not. 1000 is a round number, the result of 47000 is 425.something so the .something needs discarding.

author: ataradov
author_rank: Super Contributor
timestamp: August 21, 2018, 05:44:01 pm
content: Quote from: Simon on August 21, 2018, 05:42:36 pmYes, but what value do you actually get when comping the code?

author: Mechatrommer
author_rank: Super Contributor
timestamp: August 21, 2018, 05:53:55 pm
content: Quote from: ataradov on August 21, 2018, 05:04:46 pma good compiler will know how to promote to 32 bit integer operation but i've not seen automatic promotion to floating point operation...Quote from: ataradov on August 21, 2018, 05:44:01 pmthe value is 425.53191489361702127659574468085 he should get 425 or 426 depending on compiler. he got round off error nevermind...

author: ataradov
author_rank: Super Contributor
timestamp: August 21, 2018, 05:55:48 pm
content: Quote from: Mechatrommer on August 21, 2018, 05:53:55 pmNot really. Compiler promotes things to 'int' regardless of its size. The problem is that on AVR int is 16 bits.

author: Simon
author_rank: Unknown
timestamp: August 21, 2018, 06:04:22 pm
content: Well i tried making the variable a float.... nothing. I can of course use UL for the macro values.

author: Mechatrommer
author_rank: Super Contributor
timestamp: August 21, 2018, 06:10:42 pm
content: Quote from: ataradov on August 21, 2018, 05:55:48 pmsince he stated he got 425, so its round off error. if its overflow problem, he should get something nonsense like 6060. anyway, either RO or OF, it will be either RO or OF problem

author: ataradov
author_rank: Super Contributor
timestamp: August 21, 2018, 06:10:59 pm
content: You need to figure out where the actual evaluation happens. C preprocessor does not do floats, so if the expression is evaluated by the preprocessor, the result will be integer. But with casts all over the place, the compiler will do evaluation. But if all things going in are integers, then the result is going to be integer as well. You need to explicitly cast things to floats.

author: ataradov
author_rank: Super Contributor
timestamp: August 21, 2018, 06:12:00 pm
content: Quote from: Mechatrommer on August 21, 2018, 06:10:42 pmThe way I read it, he wants to get 425, but getting something else. What exactly - I have no clue.

author: Mechatrommer
author_rank: Super Contributor
timestamp: August 21, 2018, 06:17:37 pm
content: Quote from: ataradov on August 21, 2018, 06:12:00 pmhe answered you twice... we should ask him again if 19000 works.

author: Simon
author_rank: Unknown
timestamp: August 21, 2018, 06:20:54 pm
content: Quote from: ataradov on August 21, 2018, 06:10:59 pmwell i tried casting the variable calculation as float although variable is 16 bit. I have no idea what the value is. judging by how the system behaves much larger than it should be so I guess an overflow?Is there a way of finding out what atmel studio is calculating it to? It can be done as a macro or as a variable it does not matter as it is a constant. I just want to be able to set the speed in RPM instead of keep working out the period counts for that RPM's frequency.

author: Simon
author_rank: Unknown
timestamp: August 21, 2018, 06:21:18 pm
content: Quote from: Mechatrommer on August 21, 2018, 06:17:37 pmNo idea, can tell you tomorrow.

author: Simon
author_rank: Unknown
timestamp: August 21, 2018, 06:24:46 pm
content: I suppose it is that.20'000*3 < 2^16.47'000*3 > 2^16

author: hamster_nz
author_rank: Super Contributor
timestamp: August 21, 2018, 09:19:16 pm
content: Quote from: ataradov on August 21, 2018, 06:10:59 pmAs far as I knew the C processor does't do math at all, but trusting Ataradov's track record....Code:$ cat pptest.c#include <stdio.h>#define A (2)#define B (1+1)int main(int argc, char *argv[]) {#if A == Bprintf("Equal\n");#elseprintf("Not equal\n");#endif}$ gcc -o pptest pptest.c$ ./pptestEqual$Oh, that IS interesting! So "(2) == (1+1)" and I checked that "(2) == (1+1+1)" is false.Suddenly a rabbit hole appears...Code:#include <stdio.h>#define A (Y)#define B (N)int main(int argc, char *argv[]) {#if A == Bprintf("Equal\n");#elseprintf("Not equal\n");#endif}$gcc -o pptest pptest.c$ ./pptestEqualWFT - how can "(Y) == (N)"? - Let me guess, as 'Y' is undefined it is 0, and so is 'N'.Must look away before I start reading the C standards...

author: ataradov
author_rank: Super Contributor
timestamp: August 21, 2018, 10:01:42 pm
content: Yep.Although in this case preprocessor would not do any evaluation, if it is a simple define that is later used in the code (define as a simple substitution).The only way preprocessor will get to the evaluation if this define is later used in another preprocessor expression. And casts there will result in direct errors.