I'm using two different variable to divide in the calculation with the variable from int and double. These work fine when I use something like:
int cost
cost = 40;
cost = (cost / 400) * 20 * 2;
For this the method works fine and I get the right result which is 4, but when I use the variable cost and put it in the header instead, like:
#define cost 40
int total_cost;
total_cost = (cost / 400) * 20 * 2;
this always results in 0 for me and I don't know why. Even if I use printf with %d or %f this still gives me a result of 0.
You are doing integer division - which rounds down.
Therefore:
cost / 400
is returning zero because cost = 40 and 40 / 400 rounds down to zero.
What you should do is use a floating-point type like double.
EDIT:
double cost
cost = 40;
cost = (cost / 400) * 20 * 2;
and
#define cost 40
double total_cost;
total_cost = ((double)cost / 400) * 20 * 2;
Order of operations, and Integer Division.
Integer Division always truncates. Mathematically, 40/400 = .1 - but that's not an integer. The remainder is thrown away, leaving you with: 40 / 400 = 0.
Order of operations means that the division is done first, in your example. Since the order of multiplication and division doesn't matter too much (mathematically speaking), try changing the order:
total_cost = cost * 20 * 2 / 400;
Multiplication happens first, division last, giving you:
40 * 20 * 2 / 400 = 800 * 2 / 400 = 1600 / 400 = 4
Related
I need to convert a double/float angle to the range of [-180,180] by adding or subtracting 360. The remainder function works, but I am not sure why.
x = remainder (x, 360);
Why does this produce a range of [-180,180] and not [0,359.99999...]?
I understand that remainder and mod are the same for positive numbers, but they work differently for negative numbers... I just have not seen a good explanation of what is happening.
I'm happy that this works of course, but I don't really understand why.
Taken from cppreference:
The IEEE floating-point remainder of the division operation x/y calculated by this function is exactly the value x - n*y, where the value n is the integral value nearest the exact value x/y. When |n-x/y| = ½, the value n is chosen to be even.
In contrast to fmod(), the returned value is not guaranteed to have the same sign as x.
If the returned value is 0, it will have the same sign as x.
What's happening here is the function remainder(x, y) rounds to the nearest integer value, times your y and then subtracts the result from x.
Example:
remainder(160.0f, 360.0f)
result = 160 - round(160.0f / 360.0f) * 360
result = 160 - round(0.44f) * 360
result = 160 - (0 * 360)
result = 160.0f
Example2:
remainder(190.0f, 360.0f)
result = 190 - round(190.0f / 360.0f) * 360
result = 190 - round(0.53f) * 360
result = 190 - (1 * 360)
result = -170.0f
Thus you could end up having negative numbers depending on your input variable.
I'm working via a basic 'Programming in C' book.
I have written the following code based off of it in order to calculate the square root of a number:
#include <stdio.h>
float absoluteValue (float x)
{
if(x < 0)
x = -x;
return (x);
}
float squareRoot (float x, float epsilon)
{
float guess = 1.0;
while(absoluteValue(guess * guess - x) >= epsilon)
{
guess = (x/guess + guess) / 2.0;
}
return guess;
}
int main (void)
{
printf("SquareRoot(2.0) = %f\n", squareRoot(2.0, .00001));
printf("SquareRoot(144.0) = %f\n", squareRoot(144.0, .00001));
printf("SquareRoot(17.5) = %f\n", squareRoot(17.5, .00001));
return 0;
}
An exercise in the book has said that the current criteria used for termination of the loop in squareRoot() is not suitable for use when computing the square root of a very large or a very small number.
Instead of comparing the difference between the value of x and the value of guess^2, the program should compare the ratio of the two values to 1. The closer this ratio gets to 1, the more accurate the approximation of the square root.
If the ratio is just guess^2/x, shouldn't my code inside of the while loop:
guess = (x/guess + guess) / 2.0;
be replaced by:
guess = ((guess * guess) / x ) / 1 ; ?
This compiles but nothing is printed out into the terminal. Surely I'm doing exactly what the exercise is asking?
To calculate the ratio just do (guess * guess / x) that could be either higher or lower than 1 depending on your implementation. Similarly, your margin of error (in percent) would be absoluteValue((guess * guess / x) - 1) * 100
All they want you to check is how close the square root is. By squaring the number you get and dividing it by the number you took the square root of you are just checking how close you were to the original number.
Example:
sqrt(4) = 2
2 * 2 / 4 = 1 (this is exact so we get 1 (2 * 2 = 4 = 4))
margin of error = (1 - 1) * 100 = 0% margin of error
Another example:
sqrt(4) = 1.999 (lets just say you got this)
1.999 * 1.999 = 3.996
3.996/4 = .999 (so we are close but not exact)
To check margin of error:
.999 - 1 = -.001
absoluteValue(-.001) = .001
.001 * 100 = .1% margin of error
How about applying a little algebra? Your current criterion is:
|guess2 - x| >= epsilon
You are elsewhere assuming that guess is nonzero, so it is algebraically safe to convert that to
|1 - x / guess2| >= epsilon / guess2
epsilon is just a parameter governing how close the match needs to be, and the above reformulation shows that it must be expressed in terms of the floating-point spacing near guess2 to yield equivalent precision for all evaluations. But of course that's not possible because epsilon is a constant. This is, in fact, exactly why the original criterion gets less effective as x diverges from 1.
Let us instead write the alternative expression
|1 - x / guess2| >= delta
Here, delta expresses the desired precision in terms of the spacing of floating point values in the vicinity of 1, which is related to a fixed quantity sometimes called the "machine epsilon". You can directly select the required precision via your choice of delta, and you will get the same precision for all x, provided that no arithmetic operations overflow.
Now just convert that back into code.
Suggest a different point of view.
As this method guess_next = (x/guess + guess) / 2.0;, once the initial approximation is in the neighborhood, the number of bits of accuracy doubles. Example log2(FLT_EPSILON) is about -23, so 6 iterations are needed. (Think 23, 12, 6, 3, 2, 1)
The trouble with using guess * guess is that it may vanish, become 0.0 or infinity for a non-zero x.
To form a quality initial guess:
assert(x > 0.0f);
int expo;
float signif = frexpf(x, &expo);
float guess = ldexpf(signif, expo/2);
Now iterate N times (e.g. 6), (N based on FLT_EPSILON, FLT_DECIMAL_DIG or FLT_DIG.)
for (i=0; i<N; i++) {
guess = (x/guess + guess) / 2.0f;
}
The cost of perhaps an extra iteration is saved by avoiding an expensive termination condition calculation.
If code wants to compare a/b nearest to 1.0f
Simply use some epsilon factor like 1 or 2.
float a = guess;
float b = x/guess;
assert(b);
float q = a/b;
#define FACTOR (1.0f /* some value 1.0f to maybe 2,3 or 4 */)
if (q >= 1.0f - FLT_EPSILON*N && q <= 1.0f + FLT_EPSILON*N) {
close_enough();
}
First lesson in numerical analysis: for floating point numbers x+y has the potential for large relative errors, especially when the sum is near zero, but x*y has very limited relative errors.
I have this equation in solving the temperature from a temperature sensor.
variables are:
unsigned char AD_DATA; values is usually 100- 110;
int TEMP;
the original equation:
TEMP = 50 - (AD_DATA * 175) / 1000;
I changed that to:
TEMP = 500 - (AD_DATA * 1750) / 1000;
the reason for this is because TEMP is an integer, and thus on the first equation when it is calculated that there is a decimal it will be automatically rounded, so i changed it so that decimal will be included in the number.
The reason why I am not using float is because in the MCU I am using, whenever I declare a float variable inside the ISR(interrupt service routine) it will return an error thus I needed to be creative in using only INT, double will also return an error.
Now using an AD_DATA value of 100
the 1st equation will result to: 32.5, but since its an int it is now 33.
the 2nd equation should output 325, but in my output is 521
I need to include the decimal in my display thus it is really important for it to be included in the equation.
My ISR routine:
__interrupt void ADC_int(void){
IO_ADCSH.bit.INT = 0;
AD_DATA = IO_ADCRLH.DATA8;
TEMP = 500 - (AD_DATA * 1750) / 1000;
}
MCU specs
int 2bytes
long 4bytes
unsigned char 1byte
As a quick hack, you can replace (AD_DATA * 1750) / 1000 by (AD_DATA * 7) / 4.
For more ideas, read below.
Note that by changing
TEMP = 50 - (AD_DATA * 175) / 1000;
to
TEMP = 500 - (AD_DATA * 1750) / 1000;
you changed the meaning of the TEMP variable. Assuming it means "temperature" (doesn't really matter), it meant "temperature in degrees", and now it means "temperature in units of 1/10 degree". However, why did you multiply by 10? Just for convenience, I guess - you are not obliged to use powers of 10 for your units. You can use any other number, provided you remember what it was, and treat the result TEMP accordingly (e.g. divide it by 10 when printing it out). So the best number to use is 40: it eliminates a division (or rather, postpones it to later lines of code) and so avoids a loss of precision.
TEMP_MULTIPLIED_BY_40 = 2000 - AD_DATA * 7;
My first guess according to the information you gave,
is that the register length is 16bits causing the operand to overflow when you multiply AD_DATA by 1000.
the largest value a int could hold is 32762 (from the top of my head , more like 0x7FFF), even unsigned it is insufficient to hold AD_DATA*1000 ( wich in you case would be 18*1000=18000 ), the value will be truncated to 16bits, giving a negative number in the process.
you can fix that by specifying the length of your operator in your expression and casting AD_DATA to a 32bit word.
INFORMATION
My c++ program has no whole program optimization, has a Multi-Byte Character Set, and has enabled C++ Exceptions with SEH Exceptions (/EHa).
The following code reads information and then uses the read information in a simple math equation to determine the outcome.
PROBLEM
Here is an example to the situation that occurs!
For argument sake, underneath will show predetermined integer values, then the logic when the code is executed with these values.
healthalert = 19;
healthpercentage = 0; // THE PROBLEM IS HERE
health = 840;
fixedhealth = 840; // THIS SHOULD BE 885 AND NOT 840; IT IS 840 DUE TO HEALTHPERCENTAGE BEING 0 WHEN IT SHOULDN'T BE!
So in the first line of code determining the value of healthalert, the value is set to 19.
HOWEVER, when the equation for healthpercentage is calculated, even though healthalert is set to 19, the outcome for healthpercentage is zero?!?!?!?!!? WHY is this?
The next line is then executed and the value of health is 840.
Lastly, the value of fixedhealth is also 840; however, this should not be the case as it should be around 885. The reason fixedhealth is 840 is due to the math equation for healthpercentage outcoming to 0 when it shouldn't be!
Please help!
You mention SEH exceptions, but it looks like a simple case of integer division to me. You say healthalert is 19. Therefore 20 - healthalert is 1. Therefore, (20 - healthAlert)/20 is zero, because all the numbers involved are integers. Change that 20 to a 20.0, then cast back to an int at the end, and you should be fine.
Edit: Or do what Dark Falcon suggested seconds before I hit submit. :)
You don't give the variable types, but I'll bet they are integers. In that case, you're doing integer division, which truncates any fractional portion.
healthpercentage = (20 - healthalert) / healthalert * 100;
healthpercentage = (20 - 19) / 19 * 100;
healthpercentage = (int)(1 / 19) * 100;
healthpercentage = 0 * 100;
healthpercentage = 0;
If you want to continue to use integers, reorder operations so the multiplication is first:
healthpercentage = (20 - healthalert) * 100 / healthalert;
healthpercentage = (20 - 19) * 100 / 19;
healthpercentage = 1 * 100 / 19;
healthpercentage = (int)(100 / 19);
healthpercentage = 5;
Of course, even with this, the numbers don't match what you specified, so I don't understand your math. Perhaps this will still set you on the right track, however.
I have the following in a program (part of a much larger function, but this is the relevant testing bit):
int test = 100 + (100 * (9 / 100));
sprintf (buf, "Test: %d\n\r", test);
display_to_pc (buf, player);
Basically it amounts to:
x = a + (a * (b / 100))
Where a is a given figure, b is a percentage modifier, and x is the result (the original plus a percentage of the original)... I hope that makes sense.
It gives me:
Test: 100
I thought the math in my head might be wrong, but I've checked several calculators and even the expression evaluator in my IDE, and they all give me the expected result of 109 for the first expression.
Can anyone enlighten me as to what I'm missing here?
Thanks much. :)
Replace
int test = 100 + (100 * (9 / 100));
with
int test = 100 + (100 * 9 / 100);
// x = a + (a * b / 100)
and it will work as expected. 9 / 100 is performed using integer division; the nearest integer to .09 is 0 (and 0 * 100 is still 0).
Doing the multiplication first results in 900 / 100, which gives you the 9 that you were expecting.
If you need more than integer precision, you may need to go the floating point route.
You're using integer math.
9/100 = 0.
100 + (100 * (0) = 100.
Your calculators use floating point math, and can handle decimals appropriately.
As others have pointed out, the problem is that you are doing integer arithmethic. You need to do the calculation as floating point by casting the variable to double or using a double constant, then allow truncation to give you just the integer portion.
x = a + (a * (b / 100.0));
or
x = a + (a * ((double)b / 100)));
Your mistake is that 9 / 100 is interpreted as integer division, and evaluates to 0 and not 0.09.
You can write 9 / 100.0 instead, or rearrange the expression.
int test = 100 + (100 * (9 / 100));
9/100 = 0
0 * 100 = 0
100 + 0 = 100
you are using integer division so 9 / 100 is zero so test = 100 + 0 = 100
Use Daniel L's answer if you will only be working with expressions that will result in whole integer values. If the values you'll be working with are less clean, use double literals instead of integer literals:
int test = 100.0 + (100.0 * (9.0 / 100.0));
The answer of 9/10 gets truncated to 0, and then you multiply that by 100, and then add 100 to it.
Change:
int test = 100 + (100 * (9 / 100));
to
int test = (int)(100 + (100 * (9 / 100.0)));
and see if it works as expected.
EDIT: wow. Lots of answers while I was typing. Most of them will work, too.
You should be using floating point arithmetic so 9/100 becomes 0.09.
int test = 100.0 + (100.0 * 9.0 / 100.0);
You are using integers for your variable types, so the inner most expression (9 / 100) will result in a 0. Then the next expression would be 100 * 0, which is 0, and finally 100 + 0...
To get your desired result try using float instead:
float test = 100.0 + (100.0 * (9.0 / 100.0));
printf("result: %0.2f\n", test);