Conversion of float to int changes the value - c

I've looked at this question, and it doesn't appear to be the same situation.
I have a function in the check register program I'm writing that reads in a dollar amount from the user, validates it wasn't entered with fractional cents, and checks with the user that it was entered correctly. What I'm getting, though, is that after multiplying the float value that was entered by 100 and truncating with (int), the value changes. For instance, if I enter 1118.58, I can (via debug printf statements) verify that 1118.58 was scanned and assigned to amt correctly, and my while conditional (int)100 * amt == 100 * amt is correctly testing as TRUE, but after conversion to integer, the integer value is stored as 111857. More perplexing, it doesn't happen with every value (though I'm just getting going well on testing, this is the first entry I've seen change this way).
I'm using gcc on Kubuntu 14.04 64-bit, with C99 standard setting in my compile command.
Here's the function that's giving the problem (presuming you don't want/need to see 1300 lines of the complete program). Note: I have Boolean values and operators defined in a header file for my convenience -- I've recently discovered there's a standard way to do that, but haven't converted my header file yet.
int get_amt (void)
{
float amt;
int scanned, i_amt;
int success = FALSE;
char yn = '\0';
while (NOT success)
{
scanned = scanf("%f%*c", &amt);
/* validate and verify amount */
if (scanned >= 1 AND (int)100*amt == 100*amt AND amt <= 100000)
{
i_amt = (int)(100 * amt);
printf("\n amt = %4.2f i_amt = %i", amt, i_amt);
printf("\nYou entered $%i.%.2i -- Correct (Y/n)?", i_amt/100, i_amt%100);
scanf("%c%*c", &yn);
if (yn == '\0' OR yn == 'Y' OR yn == 'y')
success = TRUE;
}
}
return (i_amt);
}
And here's an output sample with the debug print statement:
Enter deposit amount (dollars and cents): $ 1118.58
amt = 1118.58 i_amt = 111857
You entered $1118.57 -- Correct (Y/n)?
Why is this happening, and how do I fix it?
After discussion in the comments below, I've converted the function to use integers, so there's no question of float precision (I hadn't really thought about just how little precision a standard float has on a 64-bit OS and compiler). Here's the updated version, which can't give this failure because there are no floats:
int get_amt (void)
{
int scanned, amt1, amt2;
int success = FALSE;
char yn = '\0';
while (NOT success)
{
scanned = scanf("%i.%i%*c", &amt1, &amt2);
/* validate and verify amount */
if (scanned >= 1)
{
printf("\nYou entered $%i.%.2i -- Correct (Y/n)?", amt1, amt2);
scanf("%c%*c", &yn);
if (yn == '\0' OR yn == 'Y' OR yn == 'y')
success = TRUE;
}
}
return (100*amt1 + amt2);
}

As #MitchWheat has already alluded to in a comment above, it is likely that when you print out the float, it rounds up, whereas when you calculate the int, it simply truncates. Get around this by using the round function. I.e., i_amt = round(100 * amt);, which will round the number in the same manner as the float is rounded.

Related

Store doubles in an array in C

I really need help to store double values in a double array. I am trying using scanf_s and it works. But if I try to input more than 4 values, my program crashes and returns me the error code 3
I actually need a dynamic array, but as I was getting too many errors with that, I changed and I'm trying to use a common array, just so I can get at least some marks for this project.
This is the code I am using now...
int main()
{
printf("Enter white-space separated real numbers. Terminate input with ^Z\n");
//get the dynamic array
double numSet[1000] = { 0 };
int size = 0;
double number;
while (scanf_s("%lf", &number) == 1)
{
numSet[size] = number;
size++;
}
//sort the array using qsort
//range of the array
double min = numSet[0];
double max = numSet[size - 1];
//get the mean
double sum = 0.0;
for (size_t i = 0; i < size; i++)
{
sum += numSet[i];
}
double mean = sum / size;
printf("Range: [%.2f ... %.2f]\n", min, max);
printf("Arithmetic mean is: %f", mean);
}
I have two problems:
Is a warning about buffer overrun:
Warning C6385 Reading invalid data from 'numSet':
the readable size is '8000' bytes, but '-8' bytes may be read.
When I try to input more than 4 numbers, my program crashes and returns the code 3
while (scanf_s("%lf", &number) == 1)
{
numSet[size] = number;
size++;
}
instead of this use
while (scanf_s("%lf", &number) == 1 && size <= 1000)
{
numSet[size] = number;
size++;
}
Your loop goes infinitely because it has no termination character.
scanf_s only reads value from keyboard and has another parameter to set its maximum input buffer value which is useful to limit your input.
What you can do is either read size from the user before letting him enter values or you can ask every time if the user wants to add more values to the array or not.
for example:
char option = 'Y';
while ( (scanf_s("%lf", &number) == 1 && option == 'Y'){
// code to enter a new number
printf("Do you want to add more numbers? (Y/N) ");
scanf("%c", &option);
}
Also, the scanf_s function returns the number of values scanned and every time is 1 as you are always taking one double value.
So even if you remove it, it wont be of much trouble.
I think the problem is how you end the input loop, scanf_s isn't needed, please see the watch window. I simply change the end condition to some no digit char.
Code::Blocks watch window
As mentioned in the comments, it's possible for
double max = numSet[size - 1];
to evaluate as
double max = numSet[-1];
when size = 0. I'm guessing that a double is 8 bytes wide, so the compiler warns that it could try to read -1 * 8 = -8 bytes from memory.

My main while loop will run, and run again when the user enters 'y' or 'n'. Regardless of what the user says

When I added the main while loop, the program just always runs, and runs through again and with a message telling me there is invalid data (from my first input validation). Can anyone show me how to give the user the option to end the program? Basically, I just want to give the user the option to end the program by pressing 'y or 'n'. Would be open to hearing new ideas, such as using a for, or do while loop! I just want the program to go through. I want the user to be able to go through as many times as they want, while having the option to leave after each run through.
#include <stdio.h>
//Declare functions
void displayWelcome(void);
double getAverage(double yards, double carries);
void endMessage(void);
int main()
{
//Declare variables
double yards, carries, average, bestAverage;
char again = 'y';
//Call function to display welcome message
displayWelcome();
while (again == 'y' || again =='Y') {
//Prompt user for the number of yards,
printf("Enter the number of yards:");
/*
Scan in the value of 'yards' and send user into a loop if they enter
incorrect data
While loop to validate the data of the value 'yards'
*Works with a numerical value greater than 0
*/
while ( 1 != scanf( "%lf", &yards ) || yards <= 0)
{
fflush(stdin);
printf("Enter a numerical value greater than zero:");
}
//Prompt user for the number of carries, followed by an input scan to get
//value of carries
printf("Enter the number of carries:");
/*
Scan in the value of 'yards' and send user into a loop if they enter
incorrect data
While loop to validate the data of the value 'carries'
*Works with a numerical value greater than zero
*/
while ( 1 != scanf("%lf", & carries) || carries <= 0)
{
//Refreshes the input value of the variable 'carries' and prompts the
//user to type in new value for 'carries'
fflush(stdin);
printf("Enter a numerical value greater than zero:");
}
average = getAverage( yards, carries);
printf("yards:%g carries:%g average:%g\n", yards, carries, average);
//Give the user the option to run the program again
printf("Would you like to run the program again? Enter (y)es or (n)o\n");
scanf("%c\n", &again);
}
endMessage();
return 0;
}
void displayWelcome(void)
{
printf("Welcome to Football Stats\n");
}
double getAverage(double yards, double carries)
{
double average;
average = yards + carries / 2;
return average;
}
void endMessage(void){
printf("\nThese results were brought to you by ");
}
UPDATE (QUESTION STILL UNANSWERED) It worked when I presses 'n' to stop the program. However, when I press 'y' to run it again (with the newly input code) it ALSO stops the program. So back to my question, can anyone see WHAT I am doing wrong so that I can give the user the option to close the program?
FINAL UPDATE I found the issue. I did "scanf("%c\n", &again);" (clearing the values) when I should have put "scanf("\n%c", &again);". Thank you to everyone who spent the time to help me!
while (again == 'y' || 'Y') { ...
|| doesn't work like that. && and || are used to connect complete boolean expressions. What you mean is:
while (again == 'y' || again == 'Y') { ...
In C, the expression 'Y' is just the integer 89, which C interprets as "true" because it is not zero. Thus, your first expression was
while (<something> || <true>) { ...
which is always true.
The conditions of your while loop evaluate to true. Like others have mentioned, (again == 'y' || 'Y') should be ((again == 'y') || (again == 'Y')). What I have not seen otherwise mentioned is that you also initialize again to 'n', which would then evaluate to false on the first run. Instead of initializing again, you could instead transform it do a do-while loop so you always go into the loop on the first time and then evaluate the condition.
do {
...
} while((again == 'y') || (again == 'Y'));
Try:
while (again == 'y' || again == 'Y')
Instead of:
while (again == 'y' || 'Y')
Otherwise, your program thinks you only want to evaluate 'Y', which is always true (i.e. non-zero).

Creating a Vector calculator append function. Attempting to add any value to it

So I'm having some more trouble with my vector calculator here and I'm not entirely sure of how I can get a float value to append to a vector. The append function is made and works properly, but the only problem I have is a case of "What if the user wants to put a 0 in the vector?"
Right now, I'm using a check to see if the float is 0, but obviously it doesn't work because it will split out an invalid operand. Is there anyway I can see if a float value is either not entered, or is not a number? So far, here's a fragment of the part I'm having trouble with:
//Vector that is intialized
Vector * myVector = alloc_vec();
//character for the options
char optionSelect[100];
//character that picks out the selection.
char select;
//A float for the operations that require an option.
float myScales = 0;
printf("Please enter a selection: ");
fgets(optionSelect, 100, stdin);
sscanf(optionSelect, "\n%c%f", &select,&myScales);
...
else if(select == 'a')
{
if(myScales != 0)
{
myVector = extend_vec(myVector, myScales);
}
else
{
printf("No operand specified.\n");
}
}
What can I do to make sure any float value from -inf to inf can be added in, but invalid things such as letters or no input right after 'a' is selected?
Figured it out, if you set myScales to 0.0/0.0 to get a NaN(presumably?) number, and check myScales == myScales followed by the rest, and set myScales back to 0.0/0.0 it should work!

Determining if a float has a fractional part?

Here is the problem: The game Totals can be played by any number of people. It starts with a total of 100 and each player in turn makes an integer displacement between -20 and 20 to that total. The winner is the player whose adjustment makes the total equal to 5. Using only the three variables given:
total
adjustment
counter
Here is what I have so far:
#include <stdio.h>
int main (void)
{
int counter=0;
float adj;
int ttl=100;
printf("You all know the rules now lets begin!!!\n\n\nWe start with 100. What is\n");
while (ttl!=5)
{
printf("YOUR ADJUSTMENT?");
scanf("%f",&adj);
counter++;
if (adj<=20 && adj>=-20)
{
ttl=ttl+adj;
printf("The total is %d\n",ttl);
}
else
{
printf ("I'm sorry. Do you not know the rules?\n");
}
}
printf("The game is won in %d steps!",counter);
}
What I need:
When a decimal number is entered it goes to the else. How do I determine if a float has a fractional part.
You can cast the float to an int and then compare it to your original variable. If they are the same there was no fractional part.
By using this method, there is no need for a temporary variable or a function call.
float adj;
....
if (adj == (int)adj)
printf ("no fractional!\n");
else
printf ("fractional!\n");
Explanation
Since an int cannot handle fractions the value of your float will be truncated into an int (as an example (float)14.3 will be truncated into (int)14).
When comparing 14 to 14.3 it's obvious that they are not the same value, and therefore "fractional!" will be printed.
#include <stdio.h>
#include <math.h>
int main ()
{
float param, fractpart, intpart;
param = 3.14159265;
fractpart = modff (param , &intpart);
return 0;
}
http://www.cplusplus.com/reference/clibrary/cmath/modf/
modff finds the fractional part, so I guess testing whether it's equal to 0 or null will answer your question.
if you want to know whether a real number x has no fractional part, try x==floor(x).
I am only learning C so tell me if I am wrong, please.
But if instead of using
scanf("%f",&adj);
if you use:
scanf("%d%d", &adj, &IsUndef);
Therefore if the user typed anything other than a whole integer &IsUndef would not equal NULL and must have a fractional part sending the user to else.
maybe.
Using scanf() is problematic. If the user typed -5 +10 -15 -15 on the first line of input, then hit return, you'd process the 4 numbers in turn with scanf(). This is likely not what you wanted. Also, of course, if the user types +3 or more, then the first conversion stops once the space is read, and all subsequent conversions fail on the o or or, and the code goes into a loop. You must check the return value from scanf() to know whether it was able to convert anything.
The read-ahead problems are sufficiently severe that I'd go for the quasi-standard alternative of using fgets() to read a line of data, and then using sscanf() (that extra s is all important) to parse a number.
To determine whether a floating point number has a fractional part as well as an integer part, you could use the modf() or modff() function - the latter since your adj is a float:
#include <math.h>
double modf(double x, double *iptr);
float modff(float value, float *iptr);
The return value is the signed fractional part of x; the value in iptr is the integer part. Note that modff() may not be available in compilers (runtime libraries) that do not support C99. In that case, you may have to use double and modf(). However, it is probably as simple to restrict the user to entering integers with %d format and an integer type for adj; that's what I'd have done from the start.
Another point of detail: do you really want to count invalid numbers in the total number of attempts?
#include <stdio.h>
#include <math.h>
int main(void)
{
int counter=0;
int ttl=100;
printf("You all know the rules now lets begin!!!\n"
"\n\nWe start with 100. What is\n");
while (ttl != 5)
{
char buffer[4096];
float a_int;
float adj;
printf("YOUR ADJUSTMENT?");
if (fgets(buffer, sizeof(buffer), stdin) == 0)
break;
if (sscanf("%f", &adj) != 1)
break;
if (adj<=20 && adj>=-20 && modff(adj, &a_int) == 0.0)
{
counter++; // Not counting invalid numbers
ttl += adj;
printf("The total is %d\n", ttl);
}
else
{
printf ("I'm sorry. Do you not know the rules?\n");
}
}
if (ttl == 5)
printf("The game is won in %d steps!\n", counter);
else
printf("No-one wins; the total is not 5\n");
return(0);
}
Clearly, I'm studiously ignoring the possibility that someone might type in more than 4095 characters before typing return.

Averaging 3 integers

My assignment is to fix the code. I have my edited code below and the original code below that. I figure I still have a few errors in here. My error checking doesnt seem to work, and I am not sure if my getchar() function is written or working properly.
Please assume I know nothing becasue that is fairly accurate.
The code compiles, but the answer is always 2. I am about 4 hours into this piece of code with 3 more to work after this.
My code
#include <stdio.h>
double get_number(double num);
main () {
double n1,n2,n3;
double average;
printf("\nCompute the average of 3 integers\n");
printf("--------------------------------\n");
n1 = get_number(1);
n2 = get_number(2);
n3 = get_number(3);
average = (n1 + n2 + n3)/3;
printf("The average is %0.2f\n",average);
}
double get_number(double num) {
double value = 0;
char c;
int i;
printf("Please input number %d: ", num);
while (c = getchar != '\n') {
if ( (c>9) || (c<0) ) {
printf("Incorrect character entered as a number - %c\n",c);
return(0);
}
else {
value = num;
}
}
return(value);
}
Original code
#include <stdio.h>
main () {
double n1,n2,n3;
double average;
printf("\nCompute the average of 3 integers\n");
printf("--------------------------------\n");
n1 = get_number(1);
n2 = get_number(2);
n3 = get_number(3);
average = (n1 + n2 + n3)/3;
printf("The average is %0.2f\n",average);
}
double get_number(int num) {
double value = 0;
char c;
printf("Please input number %d: ", num);
while (c = getchar() != '\n') {
if ( (c<=9) && (c>=0) ) {
printf("Incorrect character entered as a number - %c\n",c);
exit(-1);
}
else {
value = 10*value + c - '0';
}
}
return(value);
}
A few issues:
1. You should be using '9' and '0', since you want the ASCII values for digit '9' (0x39) and '0' (0x30), not 0x9 and 0x0.
if ( (c>'9') || (c<'0') ) {
2. != has higher precedence than =, so you need parens. Learn operator precedence, and if you're in doubt, use parens:
3. getchar is a function not a variable.
while ((c = getchar()) != '\n') {
4. You use the wrong conversion. num is a double, so you would need %f. Or, you could make num a int.
printf("Please input number %f: ", num);
5. You never actually use c in any way (except error checking). You always return 0 or num (see your else clause), which makes no sense. The else body of the original is correct.
You got the floating point parsing all wrong and shouldn't be doing it yourself. There's an easier way:
double get_number(double num) {
double value = 0.0;
printf("Please input number %lf: ", num);
scanf("%lf", &value);
return(value);
}
The issues with the original program are:
getchar() returns an ASCII code, and the condition was wrong. When checking for boundaries, use ((c<'0') || (c>'9')).
For the exit function you need to include "stdlib.h".
For the main function to understand what is get_number, you need to either move the function to be before the main function, or you can use a forward declaration.
The assignment operator (=) has lower precedence than the inequality operator (!=), so you need to use parenthesis, like: ((c = getchar()) != '\n')
You have actually created several more issues, so I wouldn't rely on your code.
In any case, in general - it is advised you study how to use a debugger. Once your code is compiling (and for that you'll need to get accustomed to the compilation error messages), you need to start debugging your code. I suggest you take some time to learn how to set breakpoints, set watches, and go step by step into your code. That skill is absolutely essential for a good developer.
Here's how I'd go about correcting the code ...
http://ideone.com/a0UMm -- compilation errors
http://ideone.com/ljUg1 -- warnings, but it works now
http://ideone.com/Qd0gp -- no errors, no warnings, test run ok
For 1. I used the "original code" as posted by you.
For 2. I used int main(void), declared the function get_number before defining main, added parenthesis in line 20, and added #include <stdlib.h>
For 3. I added return 0; before the final } of main. I also removed the extra output that messed up the ideone interface (it looks better on an interactive interface)
Edit more tests needed to complete the task of correcting the original code

Resources