View previous topic :: View next topic |
Author |
Message |
FFT
Joined: 07 Jul 2010 Posts: 92
|
divide by zero |
Posted: Wed Nov 24, 2010 12:20 pm |
|
|
Hi All,
I get "Divide by zero" error on this code:
Code: | #define CPUCLK 48000000 // [Hz]
#define TMRDIV 8
#define TIMEOUT (1/((1/(CPUCLK/4))*TMRDIV*65536)) //interrupt counts of timer for 1 sec
void main()
{
volatile int8 Timer;
Timer=TIMEOUT; // on this row occurs 'divide by zero' error
while(1);
} |
But the result of TIMEOUT is 22.88 for calculator. |
|
|
FFT
Joined: 07 Jul 2010 Posts: 92
|
|
Posted: Wed Nov 24, 2010 12:25 pm |
|
|
I added .0 at the end of all numbers and now can compile, but why it calculates everything as int8? |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Wed Nov 24, 2010 1:13 pm |
|
|
MSVC++ 6.0 does the same thing. Here is the error message:
Quote: |
error C2124: divide or mod by zero
|
Test program for MSVC6:
Code: |
#include <stdio.h>
#define CPUCLK 48000000 // [Hz]
#define TMRDIV 8
#define TIMEOUT (1/((1/(CPUCLK/4))*TMRDIV*65536)) //interrupt counts of timer for 1 sec
//============================
void main(void)
{
unsigned char Timer;
Timer = TIMEOUT;
printf("%x \n", Timer);
} |
|
|
|
temtronic
Joined: 01 Jul 2010 Posts: 9243 Location: Greensville,Ontario
|
|
Posted: Wed Nov 24, 2010 2:12 pm |
|
|
I'd breakdown the definition of TIMEOUT, printing out the subcomputed values to see why it isn't the value(23) that you think it should be.
It's easy to think the compiler is do something wrong, but stacked(multilevel) parenthesis can get even the best programmer ! |
|
|
FFT
Joined: 07 Jul 2010 Posts: 92
|
|
Posted: Wed Nov 24, 2010 3:46 pm |
|
|
I declared all the numbers like float (8.0 etc..) as solution.
BTW, Keil for ARM does not the same thing. |
|
|
andrewg
Joined: 17 Aug 2005 Posts: 316 Location: Perth, Western Australia
|
|
Posted: Wed Nov 24, 2010 10:04 pm |
|
|
This is how I would have done it: Code: | #define TIMEOUT (getenv("CLOCK")/4/TMRDIV/65536) | Or, if you wanted rounding to the nearest integer: Code: | #define TIMEOUT ((getenv("CLOCK")/4/TMRDIV+32768)/65536) |
_________________ Andrew |
|
|
Wayne_
Joined: 10 Oct 2007 Posts: 681
|
|
Posted: Thu Nov 25, 2010 2:58 am |
|
|
This is most likely your problem
(1/(CPUCLK/4))
1/(CPUCLK/4) will be less than 1. The int part of the result will be 0.
from then on it is all down hill.
0 * val = 0 |
|
|
FFT
Joined: 07 Jul 2010 Posts: 92
|
|
Posted: Thu Nov 25, 2010 5:43 am |
|
|
@andrewg, Thanks for the equation.
Wayne_ wrote: | 1/(CPUCLK/4) will be less than 1. The int part of the result will be 0. from then on it is all down hill. 0 * val = 0 |
I already understood that, but my question was other. "why it calculates everything as int8?"
Thanks all for the valued opinions, the problem temporarily has solved by the andrewg's equation, the other way is to make all the numbers float. |
|
|
andrewg
Joined: 17 Aug 2005 Posts: 316 Location: Perth, Western Australia
|
|
Posted: Thu Nov 25, 2010 6:44 am |
|
|
FFT wrote: | "why it calculates everything as int8?" |
The compiler always treats things as the most simple type possible. It will try to fit things into an 8-bit integer first, then 16-bit, then 32-bit. I'm pretty sure it will only use floating point if you force it to, as you've done using ".0".
In your case it's not using int8, but int32. The 8 vs 32 isn't important, the fact it's an integer is. As you've found, the intermediate value of (1/12000000) is rounded down to zero due to the integer math.
When dealing with integer math, you need to consider the order of calculation to maintain accuracy and precision. _________________ Andrew |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19539
|
|
Posted: Thu Nov 25, 2010 8:17 am |
|
|
Simple answer. It doesn't use int8....
In C, the standard rule is, that for every arithmetic operation, you look at the types of the two operands, and then promote the 'lowest' types number to the higher type, and perform the arithmetic using this type.
Look at the numbers in the original sum. The _highest_ type used here, is an int32. Since this is used in the very first sum, this will be the type for the entire operation. When you perform the first division, you have 1/(a value>1), so the result in integer maths, is zero. The second division, then errors.
Now, most C's follow this rule. (as PCM programmer has pointed out VC does as well). There are 'slight' exceptions as you move into computers with more processing power (on the PC for example, if you perform 'int8' multiplications, the result is always an int16). This is because there is a hardware multiplier, that gives a 16bit result. Similarly, when you use the FPU, there is a tendency to accept a higher type result 'automatically'. This however is _not_ standard C.
Now, in the problem code, simply forcing the very first multiplier to be a float, will automatically force float to be used for every subsequent operation. So (CPUCLK/4.0), is all that is needed.
Best Wishes |
|
|
|